# 2.1-不可變集合
[原文鏈接](https://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained) **譯者:**沈義揚
## 范例
```
public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
"red",
"orange",
"yellow",
"green",
"blue",
"purple");
class Foo {
Set<Bar> bars;
Foo(Set<Bar> bars) {
this.bars = ImmutableSet.copyOf(bars); // defensive copy!
}
}
```
## 為什么要使用不可變集合
不可變對象有很多優點,包括:
* 當對象被不可信的庫調用時,不可變形式是安全的;
* 不可變對象被多個線程調用時,不存在競態條件問題
* 不可變集合不需要考慮變化,因此可以節省時間和空間。所有不可變的集合都比它們的可變形式有更好的內存利用率(分析和測試細節);
* 不可變對象因為有固定不變,可以作為常量來安全使用。
創建對象的不可變拷貝是一項很好的防御性編程技巧。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工具,如
```
public static final ImmutableSet<Color> GOOGLE_COLORS =
ImmutableSet.<Color>builder()
.addAll(WEBSAFE_COLORS)
.add(new Color(0, 191, 255))
.build();
```
此外,對有序不可變集合來說,排序是在構造集合的時候完成的,如:
```
ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
```
會在構造時就把元素排序為a, b, c, d。
### 比想象中更智能的copyOf
請注意,ImmutableXXX.copyOf方法會嘗試在安全的時候避免做拷貝——實際的實現細節不詳,但通常來說是很智能的,比如:
```
ImmutableSet<String> foobar = ImmutableSet.of("foo", "bar", "baz");
thingamajig(foobar);
void thingamajig(Collection<String> collection) {
ImmutableList<String> defensiveCopy = ImmutableList.copyOf(collection);
...
}
```
在這段代碼中,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視圖
所有不可變集合都有一個asList()方法提供ImmutableList視圖,來幫助你用列表形式方便地讀取集合元素。例如,你可以使用sortedSet.asList().get(k)從ImmutableSortedSet中讀取第k個最小元素。
asList()返回的ImmutableList通常是——并不總是——開銷穩定的視圖實現,而不是簡單地把元素拷貝進List。也就是說,asList返回的列表視圖通常比一般的列表平均性能更好,比如,在底層集合支持的情況下,它總是使用高效的contains方法。
## 細節:關聯可變集合和不可變集合
| **可變集合接口** | **屬于****JDK****還是****Guava** | **不可變版本** |
|:--- |:--- |:--- |
| Collection | JDK | [`ImmutableCollection`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableCollection.html) |
| List | JDK | [`ImmutableList`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableList.html) |
| Set | JDK | [`ImmutableSet`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableSet.html) |
| SortedSet/NavigableSet | JDK | [`ImmutableSortedSet`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableSortedSet.html) |
| Map | JDK | [`ImmutableMap`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableMap.html) |
| SortedMap | JDK | [`ImmutableSortedMap`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableSortedMap.html) |
| [Multiset](http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset) | Guava | [`ImmutableMultiset`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableMultiset.html) |
| SortedMultiset | Guava | [`ImmutableSortedMultiset`](http://docs.guava-libraries.googlecode.com/git-history/release12/javadoc/com/google/common/collect/ImmutableSortedMultiset.html) |
| [Multimap](http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap) | Guava | [`ImmutableMultimap`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableMultimap.html) |
| ListMultimap | Guava | [`ImmutableListMultimap`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableListMultimap.html) |
| SetMultimap | Guava | [`ImmutableSetMultimap`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableSetMultimap.html) |
| [BiMap](http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap) | Guava | [`ImmutableBiMap`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableBiMap.html) |
| [ClassToInstanceMap](http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#ClassToInstanceMap) | Guava | [`ImmutableClassToInstanceMap`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableClassToInstanceMap.html) |
| [Table](http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table) | Guava | [`ImmutableTable`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableTable.html) |
- Google Guava官方教程(中文版)
- 1-基本工具
- 1.1-使用和避免null
- 1.2-前置條件
- 1.3-常見Object方法
- 1.4-排序: Guava強大的”流暢風格比較器”
- 1.5-Throwables:簡化異常和錯誤的傳播與檢查
- 2-集合
- 2.1-不可變集合
- 2.2-新集合類型
- 2.3-強大的集合工具類:java.util.Collections中未包含的集合工具
- 2.4-集合擴展工具類
- 3-緩存
- 4-函數式編程
- 5-并發
- 5.1-google Guava包的ListenableFuture解析
- 5.2-Google-Guava Concurrent包里的Service框架淺析
- 6-字符串處理:分割,連接,填充
- 7-原生類型
- 9-I/O
- 10-散列
- 11-事件總線
- 12-數學運算
- 13-反射