不可变集合(Immutable collections)

优质
小牛编辑
119浏览
2023-12-01

不可变集合是不可被修改的, 集合的数据项是在创建的时候提供, 并且在整个生命周期中都不可改变.

Immutable对象有以下的优点:

  • 对不可靠的客户代码库来说,它使用安全,可以在未受信任的类库中安全的使用这些对象
  • 线程安全的:immutable对象在多线程下安全,没有竞态条件
  • 不需要支持可变性, 可以尽量节省空间和时间的开销. 所有的不可变集合实现都比可变集合更加有效的利用内存 (analysis)
  • 可以被使用为一个常量,并且期望在未来也是保持不变的

Immutable对象是一个很好的防御编程(defensive programming)的技术实践

问题

JDK自带的Collections.unmodifiableXXX实现的不是真正的不可变集合,当原始集合修改后,不可变集合也发生变化。

	List<String> lists = Lists.newArrayList("aa", "bb", "cc");

	List<String> unmodifiedLists = Collections.unmodifiableList(lists);
	assertEquals(3, unmodifiedLists.size());

	lists.add("dd");
	assertEquals(4, unmodifiedLists.size());

JDK自带的Collections.unmodifiableXXX实现的不可变集合存在问题:

  • 它不安全: 如果有对象reference原始的被封装的集合类,这些方法返回的集合也就不是正真的不可改变
  • 效率低: 因为它返回的数据结构本质仍旧是原来的集合类,所以它的操作开销,包括并发下修改检查,hash table里的额外数据空间都和原来的集合是一样的。

方案

com.google.common.collect.ImmutableXXX

创建Immutable集合的方法
ImmutableSet.copyOf(set);           // 使用copyOf方法
ImmutableSet.of("a", "b", "c");     // 使用of方法
ImmutableMap.of("a", 1, "b", 2);    // 使用of方法
ImmutableSet.<Color>builder()       // 使用builder 
            .add(new Color(0, 255, 255))
            .add(new Color(0, 191, 255))
            .build();
智能的copyOf方法

一般来说,ImmutableXXX.copyOf(ImmutableCollection)会避免线性复杂度的拷贝操作:

  • 这个操作有可能就利用了被封装数据结构的常数复杂度的操作。但例如ImmutableSet.copyOf(list)不能在常数复杂度下实现。
  • 这样不会导致内存泄漏-例如,你有个ImmutableList imInfolist,然后你显式操作ImmutableList.copyOf(imInfolist.subList(0, 10))。这样的操作可以避免意外持有不再需要的在hugeList里元素的reference。
  • 它不会改变集合的语意-像ImmutableSet.copyOf(myImmutableSortedSet)这样的显式拷贝操作,因为在ImmutableSet里的hashCode()和equals()的含义和基于comparator的ImmutableSortedSet是不同的。

这些特性有助于最优化防御性编程的性能开销

asList方法

所有的immutable集合都以asList()的形式提供了ImmutableList视图(view).
比如,你把数据放在ImmutableSortedSet,你就可以调用sortedSet.asList().get(k)来取得第k个元素的集合。
返回的ImmutableList常常是个常数复杂度的视图,而不是一个真的拷贝。

guava中的不可变集合
可变类型集合来源Guava中的不可变集合
CollectionJDKImmutableCollection
ListJDKImmutableList
SetJDKImmutableSet
SortedSet/NavigableSetJDKImmutableSortedSet
MapJDKImmutableMap
SortedMapJDKImmutableSortedMap
MultisetGuavaImmutableMultiset
SortedMultisetGuavaImmutableSortedMultiset
MultimapGuavaImmutableMultimap
ListMultimapGuavaImmutableListMultimap
SetMultimapGuavaImmutableSetMultimap
BiMapGuavaImmutableBiMap
ClassToInstanceMapGuavaImmutableClassToInstanceMap
TableGuavaImmutableTable