Immutable Collections
个人博客
http://www.taociabc.com/wordpress/2018/01/06/guava%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E7%B3%BB%E5%88%97-immutable-collections/
英文原文 https://github.com/google/guava/wiki/ImmutableCollectionsExplained
不可修改的集合
public static final ImmutableSet COLOR_NAMES = ImmutableSet.of( "red", "orange", "yellow", "green", "blue", "purple");
class Foo {
final ImmutableSet bars;
Foo(Set bars) {
this.bars = ImmutableSet.copyOf(bars); // defensive copy!
}
}
Why?
不可修改的对象有许多优势,包括:
* 可以安全的被不受信任的外部库使用,而不用担心数据被篡改
* 线程安全:可被多线程使用,没有竞争风险
* 不必支持修改,在这种假设前提下可以节省时间和空间,所有不可变的集合实现要比可变的集合更加高效 分析
使对象拷贝不可变是一种好的防御性编程技术,Guava提供了简单、易于使用的多种基本的Collection类型,包括Guava自己的Collection变体。
JDK提供Collections.unmodifiableXXX方法,但从我们的观点看,这些是
* 笨拙和冗长的;在任何你想进行防御性拷贝编程时都不太好用;
* 不安全:在任何人都不持有原始集合的引用时,返回的集合才真的是不可改变的。换言之,JDK提供的实现返回的不可变集合还是可能被改变的
* 低效:数据结构仍然有可变集合的性能开销,包括并发修改检测,占用额外的hash tables空间。
当你不期望修改一个集合,或期望一个集合保持常量状态,一个好的实践就是把它进行防御性拷贝进一个不可变集合中。
How?
一个 ImmutableXXX 集合可以通过许多方式创建:
* 使用 copyOf 方法,例如,ImmutableSet.copyOf(set)
* 使用 of 方法, 例如, ImmutableSet.of("a", "b", "c") 或 ImmutableMap.of("a", 1, "b", 2)
* 使用Builder , 例如:
public static final ImmutableSet GOOGLE_COLORS = ImmutableSet.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在安全的情况下是尝试避免拷贝数据的,这很有用 -- 额外的细节并没有指定,但是在实现上通常是很智能的,例如:
ImmutableSetfoobar = ImmutableSet.of("foo", "bar", "baz");thingamajig(foobar);void thingamajig(Collectioncollection) { ImmutableListdefensiveCopy = ImmutableList.copyOf(collection);
...
}
在这个代码中,ImmutableList.copyOf(foobar)很聪明的仅仅返回foobar.asList(),从ImmutableSet来看这是一个恒定时间。
一般的情况下,ImmutableXXX.copyOf(ImmutableCollection) 尝试避免线性时间的拷贝,如果
* 它可以使用潜在的数据结构,在恒定的时间下。例如,ImmutableSet.copyOf(ImmutableList)不能在恒定的时间下完成。
* 它不会引起内存泄漏 -- 例如,如果你有一个很大的 ImmutableList hugeList,并且你做ImmutableList.copyOf(hugeList.subList(0, 10))这种操作,则显示的复制,因为这样可以避免意外的引用到hugeList中不必要的元素
* 它不改变语义 -- 因此ImmutableSet.copyOf(myImmutableSortedSet)将执行显示复制,因为ImmutableSet使用的 hashCode() 和 equals与ImmutableSortedSet的基于比较器的行为有不同的语义。
网友评论