因此,我想看看番石榴提供的一些集合创建模式,以及它提供的某些不可变集合类型。
如果您没有看过我以前的文章,则可能要从这里开始:
番石榴第1部分– MultiMaps
番石榴第2部分– BiMaps
番石榴第3部分–多组
Guava的所有集合实现都包含一个或多个静态create
方法,这些方法可以实现您所期望的,并且通常提供一种更为简洁的实例化集合类的方法。 这是创建ArrayListMultimap的两种不同方法
Multimap<String,String> multimap1 = new ArrayListMultimap<String,String>();Multimap<String,String> multimap2 = ArrayListMultimap.create();
好的,因此其中没有太多内容(在此示例中为12个字符),但是从我的角度来看,您正在删除一些冗余,我们真的需要两次重现泛型类型信息吗?
很好,很遗憾,Sun没想到在创建Java 5时向其Collection类型添加create方法!
同样,番石榴在这里为您提供帮助,并提供了一些用于处理标准集合类型的实用程序类。 com.google.common.collect.Lists , com.google.common.collect.Sets和com.google.common.collect.Maps
这些都提供了几种格式为new CollectionType ()
,下面是一些示例
List<String> myList1 = new ArrayList<String>(); //old wayList<String> myList2 = Lists.newArrayList(); //guava waySet<String> mySet1 = new HashSet<String>(); //old waySet<String> mySet2 = Sets.newHashSet(); //guava way
由于“ new”方法是静态的,因此您可以通过使用静态导入来剪切出更多字符,即…
import static com.google.common.collect.Lists.newArrayList;import static com.google.common.collect.Sets.newHashSet;//elsewhere in codeList<String> myList2 = newArrayList();Set<String> mySet2 = newHashSet();
明智的按键方式是,使用番石榴方法并不能真正节省很多,所以我想这和其他任何东西都一样。 我个人认为,番石榴的方法读起来要好得多,尽管我认为我不会使用静态导入。
到目前为止,还不错,但是几乎没有崩溃的余地,下一步呢?
不变的收藏
这些本质上是集合对象,创建后就无法更改,并且出于各种原因很有用。 Guava为大多数常规Collection接口提供了Immutable实现: ImmutableList , ImmutableSet和ImmutableMap ,以及某些Guava集合接口( ImmutableMultimap等)的不可变实现。
我对它们的主要用途是创建静态常量。 例如,假设您出于某种目的需要对一组字符串进行硬编码。
一种做到这一点的方法可能是,例如。
private static final Set<String> farmAnimals =new HashSet<String>(Arrays.asList('Cow','Pig','Sheep'));
它看起来并不好看,并且存在一个主要问题。 任何可以访问此Set的代码都可以对其进行更改,这可能导致各种意外问题。
我们不能只使用Collection.unmodifiableSet(Set s)
来解决这个问题吗?
好吧,在这个特定的例子中,我想我们可以写……
private static final Set<String> farmAnimals =Collections.unmodifiableSet(new HashSet<String>(Arrays.asList('Cow','Pig','Sheep')));
…但是这开始显得有些笨拙,而且无法unmodifiable
方法还有另一个问题。 它们仅返回集合的不可修改视图,如果您引用原始集合,则仍然可以对其进行更改!
尽管在上一个示例中这可能不是问题,但我仍然认为更好的方法是使用ImmutableSet
private static final Set<String> farmAnimals = ImmutableSet.of('Cow','Pig','Sheep');
是不是更好呢! 还有其他几种创建它们的方法,下面是一些示例:
// use copyOf()...public void doStuffWithList(List<Object> unsafeList) {List<Object> safeList = ImmutableList.copyOf(unsafeList);}
// use a builder...public Map<String,Integer> makeImmutableMap() {ImmutableMap.Builder<String,Integer> mapBuilder = new ImmutableMap.Builder<String,Integer>();Entry<String,Integer> entry = null;while((entry = getEntry()) != null) {mapBuilder.put(entry.getKey(), entry.getValue());}return builder.build();}
那么,使用不可变集合还有其他优势吗?
好吧,有几个。 它们可以大大简化逻辑,尤其是在多线程环境中。 如果线程仅具有对对象的读取访问权限,则您无需担心复杂的线程同步逻辑
创建它们后,它们的使用效率也略有提高。 如果一个集合事先知道它需要存储什么,并且永远不会有任何变化,则可以节省各种时间和空间。 例如,大多数ArrayLists或HashMaps的实现都会为新对象保留一些未使用的空间,因此它们不必不断调整自身大小。 如果您知道永远不会有任何新对象,则无需这样做。
最后,您还可以将它们用作哈希键。 如果集合的内容无法更改,那么它的哈希码也不会改变!
有什么缺点吗?
当然,不可变对象有一个很大的缺点,那就是显而易见的。 您不能更改它们! 如果您需要更改集合,则首先需要对其进行复制。 在某些情况下(例如,并发性很重要),您实际上可能希望采用这种方法。 但是,在集合包含许多对象的情况下,这将是不切实际的,并且您可能需要一个老式的可变集合(如果需要,请完成同步代码)。
唯一需要注意的另一件事是,仅仅因为您的集合是不可变的,并不意味着它们中包含的对象是自动的。 如果可以在不可变集合中获得对对象的引用,那么没有什么可以阻止您更改该对象上的任何可变状态! 因此,最佳实践是确保您保存在不可变集合中的任何东西本身都是不可变的!
参考: Tom's Programming Blog博客上的JCG合作伙伴 Tom Jefferys从Google Guava创建的收藏和不变性 。
翻译自: https://www.javacodegeeks.com/2012/12/collection-creation-and-immutability-with-google-guava.html