不可变对象有很多优点,包括:
当对象被不可信的库调用时,不可变形式是安全的;
不可变对象被多个线程调用时,不存在竞态条件问题
不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
不可变对象因为有固定不变,可以作为常量来安全使用。
创建对象的不可变拷贝是一项很好的防御性编程技巧。guava为所有jdk标准集合类型和guava新集合类型都提供了简单易用的不可变版本。
jdk也提供了collections.unmodifiablexxx方法把集合包装为不可变形式,但我们认为不够好:
笨重而且累赘:不能舒适地用在所有想做防御性拷贝的场景;
不安全:要保证没人通过原集合的引用进行修改,返回的集合才是事实上不可变的;
低效:包装过的集合仍然保有可变集合的开销,比如并发修改的检查、散列表的额外空间,等等。
如果你没有修改某个集合的需求,或者希望某个集合保持不变时,把它防御性地拷贝到不可变集合是个很好的实践。
重要提示:所有guava不可变集合的实现都不接受null值。我们对google内部的代码库做过详细研究,发现只有5%的情况需要在集合中允许null元素,剩下的95%场景都是遇到null值就快速失败。如果你需要在不可变集合中使用null,请使用jdk中的collections.unmodifiablexxx方法。更多细节建议请参考“使用和避免null”。
不可变集合可以用如下多种方式创建:
copyof方法,如immutableset.copyof(set);
of方法,如immutableset.of(“a”, “b”, “c”)或 immutablemap.of(“a”, 1, “b”, 2);
builder工具,如
此外,对有序不可变集合来说,排序是在构造集合的时候完成的,如:
会在构造时就把元素排序为a, b, c, d。
请注意,immutablexxx.copyof方法会尝试在安全的时候避免做拷贝——实际的实现细节不详,但通常来说是很智能的,比如:
在这段代码中,immutablelist.copyof(foobar)会智能地直接返回foobar.aslist(),它是一个immutableset的常量时间复杂度的list视图。
作为一种探索,immutablexxx.copyof(immutablecollection)会试图对如下情况避免线性时间拷贝:
在常量时间内使用底层数据结构是可能的——例如,immutableset.copyof(immutablelist)就不能在常量时间内完成。
不会造成内存泄露——例如,你有个很大的不可变集合immutablelist<string>
hugelist, immutablelist.copyof(hugelist.sublist(0, 10))就会显式地拷贝,以免不必要地持有hugelist的引用。
不改变语义——所以immutableset.copyof(myimmutablesortedset)会显式地拷贝,因为和基于比较器的immutablesortedset相比,immutableset对hashcode()和equals有不同语义。
在可能的情况下避免线性拷贝,可以最大限度地减少防御性编程风格所带来的性能开销。
所有不可变集合都有一个aslist()方法提供immutablelist视图,来帮助你用列表形式方便地读取集合元素。例如,你可以使用sortedset.aslist().get(k)从immutablesortedset中读取第k个最小元素。
aslist()返回的immutablelist通常是——并不总是——开销稳定的视图实现,而不是简单地把元素拷贝进list。也就是说,aslist返回的列表视图通常比一般的列表平均性能更好,比如,在底层集合支持的情况下,它总是使用高效的contains方法。
<b>可变集合接口</b><b></b>
<b>属于</b><b>jdk</b><b>还是</b><b>guava</b><b></b>
<b>不可变版本</b><b></b>
collection
jdk
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablecollection.html">immutablecollection</a>
list
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablelist.html">immutablelist</a>
set
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutableset.html">immutableset</a>
sortedset/navigableset
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablesortedset.html">immutablesortedset</a>
map
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablemap.html">immutablemap</a>
sortedmap
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablesortedmap.html">immutablesortedmap</a>
<a href="http://code.google.com/p/guava-libraries/wiki/newcollectiontypesexplained#multiset">multiset</a>
guava
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablemultiset.html">immutablemultiset</a>
sortedmultiset
<a href="http://docs.guava-libraries.googlecode.com/git-history/release12/javadoc/com/google/common/collect/immutablesortedmultiset.html">immutablesortedmultiset</a>
<a href="http://code.google.com/p/guava-libraries/wiki/newcollectiontypesexplained#multimap">multimap</a>
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablemultimap.html">immutablemultimap</a>
listmultimap
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablelistmultimap.html">immutablelistmultimap</a>
setmultimap
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablesetmultimap.html">immutablesetmultimap</a>
<a href="http://code.google.com/p/guava-libraries/wiki/newcollectiontypesexplained#bimap">bimap</a>
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutablebimap.html">immutablebimap</a>
<a href="http://code.google.com/p/guava-libraries/wiki/newcollectiontypesexplained#classtoinstancemap">classtoinstancemap</a>
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutableclasstoinstancemap.html">immutableclasstoinstancemap</a>
<a href="http://code.google.com/p/guava-libraries/wiki/newcollectiontypesexplained#table">table</a>
<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/immutabletable.html">immutabletable</a>