Immutable Collections
Example
public static final ImmutableSet<String> COLOR_NAMES
= ImmutableSet.of( "red", "orange", "yellow", "green", "blue", "purple");
class Foo {
final ImmutableSet<Bar> bars;
Foo(Set<Bar> bars) {
this.bars = ImmutableSet.copyOf(bars); // 保护性拷贝!
}
}
Why?
Immutable 类有着很多优势,包括:
- 不被信任的库实现了安全。
- 线程安全: 能够在无竞争条件风险下被许多线程使用。
- 不需要支持变化并且在此前提下节省时间与空间。所有 immutable collection 的实现对内存的操作都比可变类更加有效率. (analysis)
- 可以期望它保持不变当做常量使用。
制作对象的不可变副本是一种很好的防错性程序设计。Guava 提供简易的 immutable版本与标准 Collection 类型, 包含 Guava's 自己的 Collection 改进.
JDK 也提供的 Collections.unmodifiableXXX 方法, 但在我们看来:
- 笨拙冗长;不能在你想做防御性拷贝的任何地方使用。
- 不安全: 如果没有任何对象拥有原始集合的拷贝返回的集合才是真正的 immutable
- 效率低: 数据结构仍然具有可变集合的所有开销,包括并发修改检查、哈希表中的额外空间等。
当你不想修改集合,或者想将该集合当做常量,一种较好的做法是做防御性拷贝进immutable collection中
重要: 任何 Guava immutable collection实现都拒绝null值. 我们对谷歌的内部代码基础做了详尽的研究,它表明在5%的情况下允许null在集合中存储,而其他95%的情况最好遇到null后快速失败。如果你想使用null,考虑一下使用Collections.unmodifiableList ,细节请访问这里 here.
How?
创建ImmutableXXX 集合的方式有很多:
- 使用 copyOf 方法,例如, ImmutableSet.copyOf(set)
- 使用 of 方法, 例如, ImmutableSet.of("a", "b", "c") or 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();
除了sorted collections, 顺序由插入时间决定. 例如,
ImmutableSet.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的一个固定时间视图。
作为一般的启发, ImmutableXXX.copyOf(ImmutableCollection) 尝试避免线性时间拷贝。
- 有可能在固定的时间内使用底层数据结构。例如, ImmutableSet.copyOf(ImmutableList) 不能在固定的时间内完成。
- 将引起内存泄漏 -- 例如, 现有 ImmutableList<String> hugeList, 对它进行 ImmutableList.copyOf(hugeList.subList(0, 10))操作, 执行一个显式拷贝,以避免在不需要的HugListor中意外引用。
- 它不会改变语义 -- 因此 ImmutableSet.copyOf(myImmutableSortedSet) 将执行显式拷贝, 因为 ImmutableSet使用的hashCode() 与 equals 有着与ImmutableSortedSet不同的比较器语义。
这有助于最小化防御编程风格的性能开销。
asList
所有的immutable collections 都通过asList()提供ImmutableList 视图, 例如 -- 即使你利用even if ImmutableSortedSet排序了数据, 你依旧可以使用sortedSet.asList().get(k)来获取第k个最小的元素。
ImmutableList 的返回是流式的-- 不总是,但经常 -- 一个固定的开销视图,而不是一个显式拷贝。也就是说,它通常比你的List 更聪明。 -- 例如, 其使用有效的contains方法去备份集合。
Details
Where?
Interface | JDK or Guava? | Immutable Version |
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 |