Example
publicstatic final ImmutableSet<String> COLOR_NAMES =ImmutableSet.of(
"red",
"orange",
"yellow",
"green",
"blue",
"purple");
classFoo{
Set<Bar> bars;
Foo(Set<Bar> bars){
this.bars =ImmutableSet.copyOf(bars);// defensive copy!
}
}
Why?
Immutable objects have many advantages, including:
不可变对象有很多优势,包括:
- Safe for use by untrusted libraries.
- 可被不可信任库安全使用
- Thread-safe: can be used by many threads with no risk of race conditions.
- 线程安全: 可被多线程使用却没有竞争的危险
- Doesn't need to support mutation, and can make time and space savings with that assumption. All immutable collection implementations are more memory-efficient than their mutable siblings (analysis)
- 不需要支持变化操作,这种设定下可以节省时间和空间. 所有不可变集合的实现相对于可变集合的同类在内存上更有效率
- Can be used as a constant, with the expectation that it will remain fixed
- 可被作为constant使用, 可变操作将抛出异常
Making immutable copies of objects is a good defensive programming technique. Guava provides simple, easy-to-use immutable versions of each standard Collection type, including Guava's own Collection variations.
使用对象的不可变copy是一种很好的防御性编程技术.Guava提供了简单易用的每种标准集合的不可变版本, 也包括一些Guava自己的集合变种.
The JDK provides Collections.unmodifiableXXX methods, but in our opinion, these can be
JDK提供Collections.unmodifiableXXX 方法, 但我们的观点是:
- unwieldy and verbose; unpleasant to use everywhere you want to make defensive copies
- 笨重冗长; 每个你想使用防御性copy的地方都会用得很不爽
- unsafe: the returned collections are only truly immutable if nobody holds a reference to the original collection
- 不安全: 返回的集合只有在没人持有原始集合的引用时才是真正的不可变
- inefficient: the data structures still have all the overhead of mutable collections, including concurrent modification checks, extra space in hash tables, etc.
- 效率低: 这种数据结构依然有所有的可变集合开销, 包括同步修改检查, 额外的hash表空间.
When you don't expect to modify a collection, or expect a collection to remain constant, it's a good practice to defensively copy it into an immutable collection.
当你不想修改一个集合,或者想要一个常量集合,把他复制到一个immutable collection是一个很好的做法
Important: Each of the Guava immutable collection implementations rejects null values. We did an exhaustive study on Google's internal code base that indicated that null elements were allowed in collections about 5% of the time, and the other 95% of cases were best served by failing fast on nulls. If you need to use null values, consider using Collections.unmodifiableList and its friends on a collection implementation that permits null. More detailed suggestions can be found here.
重点: 每个Guava不可变集合实现都排斥null值.我们在google的internal code base做了一次全力的代码调查, 发现集合中只有5%的时候存在null, 另外95%的时候最后都是应该使用快速失败来替代null.加入你需要使用null,考虑使用Collections.unmodifiableList和他那些可以允许null的朋友们.
How?
An ImmutableXXX collection can be created in several ways:
一个不可变XXX集合可以由如下几种方式创建:
-
- using the copyOf method, for example, ImmutableSet.copyOf(set)
- 使用copyOf方法, 例如, ImmutableSet.copyOf(set)
- using the of method, for example, ImmutableSet.of("a", "b", "c") or ImmutableMap.of("a", 1, "b", 2)
- 使用of方法,例如, ImmutableSet.of("a", "b", "c")或者ImmutableMap.of("a", 1, "b", 2)
- using a Builder, for example,
- 使用一个Builder, 例如:
public static final ImmutableSet<Color> GOOGLE_COLORS =
ImmutableSet.<Color>builder()
.addAll(WEBSAFE_COLORS)
.add(newColor(0,191,255))
.build();
Except for sorted collections, order is preserved from construction time. For example,
除了排序集合, 顺序在创建集合的时候是被保留的.例如
ImmutableSet.of("a","b","c","a","d","b")
will iterate over its elements in the order "a", "b", "c", "d".
遍历时它的顺序是a, b, c, d
copyOf is smarter than you think
copyOf比你想象的更聪明
It is useful to remember that ImmutableXXX.copyOf attempts to avoid copying the data when it is safe to do so -- the exact details are unspecified, but the implementation is typically "smart". For example,
记住ImmutableXXX.copyOf在保证安全的情况下会尽量避免复制原始数据是很有用的 -- 精确的细节没有指定, 但是它的实现是很聪明的,例如:
ImmutableSet<String> foobar =ImmutableSet.of("foo","bar","baz");
thingamajig(foobar);
void thingamajig(Collection<String> collection){
ImmutableList<String> defensiveCopy =ImmutableList.copyOf(collection);
...
}
In this code, ImmutableList.copyOf(foobar) will be smart enough to just return foobar.asList(), which is a constant-time view of the ImmutableSet.
这段代码, ImmutableList.copyOf(foobar)仅仅会聪明的返回foobar.asList(), 一个ImmutableSet的常量时间复杂度的方法
As a general heuristic, ImmutableXXX.copyOf(ImmutableCollection) tries to avoid a linear-time copy if
作为一个一般式启发, ImmutableXXX.copyOf(ImmutableCollection)在如下情况下会尝试避免线性时间的复制
- it's possible using the underlying data structures in constant time. For example, ImmutableSet.copyOf(ImmutableList) can't be done in constant time.
- 在常量时间内使用基础的数据结构是有可能的.例如, ImmutableSet.copyOf(ImmutableList)是不能在常量时间内完成的.
- it wouldn't cause memory leaks -- for example, if you have ImmutableList<String> hugeList, and you doImmutableList.copyOf(hugeList.subList(0, 10)), an explicit copy is performed, so as to avoid accidentally holding on to references inhugeList that aren't needed.
- 他不会造成内存泄露 -- 例如, 加入你有一个ImmutableList<String>的hugeList,并且你使用ImmutableList.copyOf(hugeList.subList(0, 10)), 执行一个明确的copy操作来避免意外持有hugeList的引用时不必要的
- it won't change semantics -- so ImmutableSet.copyOf(myImmutableSortedSet) will perform an explicit copy, because the hashCode() andequals used by ImmutableSet have different semantics from the comparator-based behavior of ImmutableSortedSet.
- 他不会改变语义 -- 所以 ImmutableSet.copyOf(myImmutableSortedSet)会执行一个显式的复制, 因为hashCode()和equals被ImmutableSet使用和给予比较器的ImmutableSortedSet会有不一样的语义
This helps minimize the performance overhead of good defensive programming style.
这帮助了最小化好的防御型编程的性能开销
asList
All immutable collections provide an ImmutableList view via asList(), so -- for example -- even if you have data stored as an ImmutableSortedSet, you can get the kth smallest element with sortedSet.asList().get(k).
所有不可变集合通过asList()方法提供了一个ImmutableList, -- 例如 -- 即使你在ImmutableSortedSet里保存了数据,你也可以使用sortedSet.asList().get(k)来获取第k小的元素
The returned ImmutableList is frequently -- not always, but frequently -- a constant-overhead view, rather than an explicit copy. That said, it's often smarter than your average List -- for example, it'll use the efficient contains methods of the backing collection.
返回的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 |
对聪明的方法ImmutableList.copyOf(Collections)的解析
/** * Returns an immutable list containing the given elements, in order. * 返回一个包含给定元素的有序不可变list * * <p>Despite the method name, this method attempts to avoid actually copying * the data when it is safe to do so. The exact circumstances under which a * copy will or will not be performed are undocumented and subject to change. * * 除开方法名不说, 这个方法在安全的时候尝试避免真正的拷贝数据.具体的情况是是否会真正复制是说不准的 * 有可能会不同情况而改变 * * <p>Note that if {@code list} is a {@code List<String>}, then {@code * ImmutableList.copyOf(list)} returns an {@code ImmutableList<String>} * containing each of the strings in {@code list}, while * ImmutableList.of(list)} returns an {@code ImmutableList<List<String>>} * containing one element (the given list itself). * * 注意如果list是一个List<String>,那么ImmutableList.copyOf(list)返回一个 * 包含list所有元素的ImmutableList<String>, 而ImmutableList.of(list)则会返回一个 * 只有一个元素(list本身)的ImmutableList<List<String>> * * <p>This method is safe to use even when {@code elements} is a synchronized * or concurrent collection that is currently being modified by another * thread. * * 这个方法即使在和正在被修改的同步集合或并发集合一起使用也是安全的 * * @throws NullPointerException if any of {@code elements} is null */ public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) { // 对于不可变集合直接使用asList()来返回他的不可变副本,asList并不会真的复制 // elements这个集合, 而是返回一个代理elements集合的集合 if (elements instanceof ImmutableCollection) { @SuppressWarnings("unchecked") // all supported methods are covariant ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList(); return list.isPartialView() ? copyFromCollection(list) : list; } return copyFromCollection(elements); }
asList()方法
public ImmutableList<E> asList() { ImmutableList<E> list = asList; return (list == null) ? (asList = createAsList()) : list; }
--> ImmutableList<E> createAsList() { switch (size()) { case 0: return ImmutableList.of(); case 1: return ImmutableList.of(iterator().next()); default: return new RegularImmutableAsList<E>(this, toArray()); } }
--> RegularImmutableAsList(ImmutableCollection<E> delegate, Object[] array) { this(delegate, ImmutableList.<E>asImmutableList(array)); }