什么是不可变集合?
比如我们想创建一个list集合,想让这个list不能在被做任何修改了,这时候我们就可以用Guava包里ImmutableSet来创建一个list
例子:
public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
"red",
"orange",
"yellow",
"green",
"blue",
"purple");
不可变集合有哪些好处呢?
- 当对象被不可信的库调用时,不可变形式是安全的;(可以交给任意逻辑去)
- 不可变对象被多个线程调用时,不存在竞态条件问题(不存在多线程里的线程安全问题)
- 不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);(节省空间)
- 不可变对象因为有固定不变,可以作为常量来安全使用。(作为常量)
不仅Guava包提供了不可变集合的版本,jdk本身也提供了Collecitons.unmodifiableXXXX方法来把集合变成不可变的形式,但JDK的有以下几个缺点:
- 笨重累赘,需要写的代码太多了。
- 不安全,如果通过原集合的引用来进行集合里元素的修改其实也是可以修改的,导致可变了。
- 效率较低。被包装过的集合本质上还是使用着原来集合的方法,导致比如并发修改list还是会有一些检查,HashMap里还有一些没有用的额外的属性。其实如果集合不可变,原来集合里的一些机制就可以没有了。
重要提示:
所有Guava不可变集合的实现都不接受null值。我们对Google内部的代码库做过详细研究,发现只有5%的情况需要在集合中允许null元素,剩下的95%场景都是遇到null值就快速失败。如果你需要在不可变集合中使用null,请使用JDK中的Collections.unmodifiableXXX方法。更多细节建议请参考“使用和避免null”。
如果使用呢?
- 使用copyOf方法,例子:ImmutableSet.copyOf(set)
- of方法,ImmutableSet.of("1","2") 或者ImmutableMap.of("key1","value1","key2","value2");
- Builder工具,例子:ImmutableXXXX.builder().add().builder();
asList视图
所有不可变集合都有一个asList()方法提供ImmutableList视图,来帮助你用列表形式方便地读取集合元素。例如,你可以使用sortedSet.asList().get(k)从ImmutableSortedSet中读取第k个最小元素。
asList()返回的ImmutableList通常是——并不总是——开销稳定的视图实现,而不是简单地把元素拷贝进List。也就是说,asList返回的列表视图通常比一般的列表平均性能更好,比如,在底层集合支持的情况下,它总是使用高效的contains方法