天天看點

[Google Guava] 2.1-不可變集合

不可變對象有很多優點,包括:

當對象被不可信的庫調用時,不可變形式是安全的;

不可變對象被多個線程調用時,不存在競态條件問題

不可變集合不需要考慮變化,是以可以節省時間和空間。所有不可變的集合都比它們的可變形式有更好的記憶體使用率(分析和測試細節);

不可變對象因為有固定不變,可以作為常量來安全使用。

建立對象的不可變拷貝是一項很好的防禦性程式設計技巧。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>