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不可变版本
CollectionJDKImmutableCollection
ListJDKImmutableList
SetJDKImmutableSet
SortedSet/NavigableSetJDKImmutableSortedSet
MapJDKImmutableMap
SortedMapJDKImmutableSortedMap
MultisetGuavaImmutableMultiset
SortedMultisetGuavaImmutableSortedMultiset
MultimapGuavaImmutableMultimap
ListMultimapGuavaImmutableListMultimap
SetMultimapGuavaImmutableSetMultimap
BiMapGuavaImmutableBiMap
ClassToInstanceMapGuavaImmutableClassToInstanceMap
TableGuavaImmutableTable
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值