Guava 集合工具(不可变集合)

不可变集合

一、不可变对象

对象的不可变形式是安全的:
1)在多线程条件下不存在竞态问题
2)不可变集合不需要考虑变化,节省空间和时间。不可变集合比可变形式有更好的内存利用率
3)不可变集合常做常量容器

创建对象的不可变拷贝是一种有效的防御性编程技巧,可以避免原来假想为不可变的对象被误改。

以ImmutableList 为例:

List<String> list = Lists.newArrayList();
list.add("FULL");
list.add("LOW");
final List<String> unmodifiableList = Collections.unmodifiableList(list);
ImmutableList<String> copiedImmutableList = ImmutableList.copyOf(list);
System.out.println(list);
System.out.println(unmodifiableList);
System.out.println(copiedImmutableList);

list.add("NORMAL");
System.out.println(list);//[FULL, LOW, NORMAL]

/* 即使是包装后的 unmodifiableXX 维护的其实不是真正“不可变” 的元素*/
System.out.println(unmodifiableList); //[FULL, LOW, NORMAL]

/* copy 后的List 是不可变的 ,对原list的修改不会反应到copy后的List上来 */
System.out.println(copiedImmutableList); //[FULL, LOW]

二、UnmofiableList与ImmutableList

java.util.Collections#unmodifiableList(List< ? extends T> list )对List的包装得到的 UnmodifiableList 并不是真正的“不可变”,JDK仍然提供了unmodifiableList 的add()、addAll()等增删改数据的API。(但是这些 API提供了也没有卵用,add后将会抛出java.lang.UnsupportedOperationException 异常)。但对list的add()将会反映到unmodifiableList 上来。

List<String> list = Lists.newArrayList("green", "red");
List<String> unmodifiableList = Collections.unmodifiableList(list);
// unmodifiableList.add("black");  
// will throw java.lang.UnsupportedOperationException
list.add("black"); // Ok 
System.out.println(unmodifiableList); //will print out words containing "black"

可见:虽然JDK也提供了Collections.unmodifiableXXX方法把集合包装为不可变形式,但
- 笨重而且累赘:不能舒适地用在所有想做防御性拷贝的场景;
- 不安全:要保证没人通过原集合的引用进行修改,返回的集合才是事实上不可变的(最重要原因)
- 低效:包装过的集合仍然保有可变集合的开销,比如并发修改的检查、散列表的额外空间,等等。

总结:不可变集合的场景:::如果你没有修改某个集合的需求,或者希望某个集合保持不变时,把它防御性地拷贝到不可变集合是个很好的实践

三、最佳实践

为了防止有人生硬地为不可变对象重新赋值,建议定义不可变集合为final变量:

final ImmutableList<String> copiedImmutableList = ImmutableList.copyOf(list);
copiedImmutableList = ImmutableList.of("red");

需要注意的是:所有Guava不可变集合的实现都不接受null值。

API: 构造不可变集合的方法:

  • copyOf方法,如ImmutableSet.copyOf(set);
  • of方法,如ImmutableSet.of(“a”, “b”, “c”)或 ImmutableMap.of(“a”, 1, “b”, 2);
  • Builder工具(推荐)
final ImmutableList<String> immutableList = ImmutableList.<String>builder()
    .add("green")
    .addAll(Lists.newArrayList("red", "black"))
    .build();
final ImmutableMap<String, Object> immutableMap = ImmutableMap.<String, Object>builder()
    .put("a", "1")
    .putAll(Maps.newHashMap())
    .build();
  • 对有序不可变集合来说,排序是在构造集合的时候完成的,如
    ImmutableSortedSet.of(“a”, “b”, “c”, “a”, “d”, “b”)。既然不可变,肯定不能在原集合上排序,因为这样会改变原有的元素位置。

四、其余类型

可变集合接口 属于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

猜你喜欢

转载自blog.csdn.net/qq_30118563/article/details/80342019