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!
}
}
不可變對象有很多優(yōu)點,包括:
創(chuàng)建對象的不可變拷貝是一項很好的防御性編程技巧。Guava 為所有 JDK 標(biāo)準(zhǔn)集合類型和 Guava 新集合類型都提供了簡單易用的不可變版本。
JDK 也提供了 Collections.unmodifiableXXX 方法把集合包裝為不可變形式,但我們認為不夠好:
如果你沒有修改某個集合的需求,或者希望某個集合保持不變時,把它防御性地拷貝到不可變集合是個很好的實踐。
重要提示:所有 Guava 不可變集合的實現(xiàn)都不接受 null 值。我們對 Google 內(nèi)部的代碼庫做過詳細研究,發(fā)現(xiàn)只有 5%的情況需要在集合中允許 null 元素,剩下的 95%場景都是遇到 null 值就快速失敗。如果你需要在不可變集合中使用 null,請使用 JDK 中的 Collections.unmodifiableXXX 方法。更多細節(jié)建議請參考“使用和避免 null”。
不可變集合可以用如下多種方式創(chuàng)建:
public static final ImmutableSet<Color> GOOGLE_COLORS =
ImmutableSet.<Color>builder()
.addAll(WEBSAFE_COLORS)
.add(new Color(0, 191, 255))
.build();
此外,對有序不可變集合來說,排序是在構(gòu)造集合的時候完成的,如:
ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
會在構(gòu)造時就把元素排序為 a, b, c, d。
請注意,ImmutableXXX.copyOf 方法會嘗試在安全的時候避免做拷貝——實際的實現(xiàn)細節(jié)不詳,但通常來說是很智能的,比如:
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 的常量時間復(fù)雜度的 List 視圖。
作為一種探索,ImmutableXXX.copyOf(ImmutableCollection)會試圖對如下情況避免線性時間拷貝:
在可能的情況下避免線性拷貝,可以最大限度地減少防御性編程風(fēng)格所帶來的性能開銷。
所有不可變集合都有一個 asList()方法提供 ImmutableList 視圖,來幫助你用列表形式方便地讀取集合元素。例如,你可以使用 sortedSet.asList().get(k)從 ImmutableSortedSet 中讀取第 k 個最小元素。
asList()返回的 ImmutableList 通常是——并不總是——開銷穩(wěn)定的視圖實現(xiàn),而不是簡單地把元素拷貝進 List。也就是說,asList 返回的列表視圖通常比一般的列表平均性能更好,比如,在底層集合支持的情況下,它總是使用高效的 contains 方法。
可變集合接口 | 屬于JDK還是Guava | 不可變版本 |
Collection | JDK | ImmutableCollection |
List | JDK | ImmutableList |
Set | JDK | ImmutableSet |
SortedSet/NavigableSet | JDK | ImmutableSortedSet |
Map | JDK | ImmutableMap |
SortedMap | JDK | ImmutableSortedMap |
Multiset | Guava | ImmutableMultiset |
SortedMultiset | Guava | ImmutableSortedMultiset |
Multimap | Guava | ImmutableMultimap |
ListMultimap | Guava | ImmutableListMultimap |
SetMultimap | Guava | ImmutableSetMultimap |
BiMap | Guava | ImmutableBiMap |
ClassToInstanceMap | Guava | ImmutableClassToInstanceMap |
Table | Guava | ImmutableTable |