003-guava 集合-不可变集合
一、概述
二、使用
2.1、不可变集合
1、为什么使用不可变集合
不可变对象有很多优点,包括:
当对象被不可信的库调用时,不可变形式是安全的;
不可变对象被多个线程调用时,不存在竞态条件问题
不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
不可变对象因为有固定不变,可以作为常量来安全使用。
所有Guava不可变集合的实现都不接受null值。我们对Google内部的代码库做过详细研究,发现只有5%的情况需要在集合中允许null元素,剩下的95%场景都是遇到null值就快速失败。如果你需要在不可变集合中使用null,请使用JDK中的Collections.unmodifiableXXX方法。更多细节建议请参考“使用和避免null”。
2、JDK中的Collections.unmodifiableXXX方法
// jdk @Test public void testJDKImmutable(){ List<String> list=new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); //通过list创建一个不可变的unmodifiableList集合 List<String> unmodifiableList= Collections.unmodifiableList(list); System.out.println(unmodifiableList); //通过list添加元素 list.add("ddd"); System.out.println("往list添加一个元素:"+list); System.out.println("通过list添加元素之后的unmodifiableList:"+unmodifiableList); //通过unmodifiableList添加元素 unmodifiableList.add("eee"); System.out.println("往unmodifiableList添加一个元素:"+unmodifiableList); }
输出
[a, b, c] 往list添加一个元素:[a, b, c, ddd] 通过list添加元素之后的unmodifiableList:[a, b, c, ddd] java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
通过运行结果我们可以看出:虽然unmodifiableList不可以直接添加元素,但是我的list是可以添加元素的,而list的改变也会使unmodifiableList改变。
所以说Collections.unmodifiableList实现的不是真正的不可变集合。
3、Guava 的immutable集合
Guava提供了对JDK里标准集合类里的immutable版本的简单方便的实现,以及Guava自己的一些专门集合类的immutable实现。当你不希望修改一个集合类,
或者想做一个常量集合类的时候,使用immutable集合类就是一个最佳的编程实践。
注意:每个Guava immutable集合类的实现都拒绝null值。我们做过对Google内部代码的全面的调查,并且发现只有5%的情况下集合类允许null值,而95%的情况下
都拒绝null值。万一你真的需要能接受null值的集合类,你可以考虑用Collections.unmodifiableXXX。
immutable集合可以有以下几种方式来创建:
1、用copyOf方法, 譬如, ImmutableSet.copyOf(set)
2、使用of方法,譬如,ImmutableSet.of("a", "b", "c")或者ImmutableMap.of("a", 1, "b", 2)
3、使用Builder类
使用
@Test public void testGuavaImmutable(){ List<String> list=new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); //ImmutableList.copyOf ImmutableList<String> imlist=ImmutableList.copyOf(list); System.out.println("imlist:"+imlist); //ImmutableList.of ImmutableList<String> imOflist=ImmutableList.of("peida","jerry","harry"); System.out.println("imOflist:"+imOflist); ImmutableSortedSet<String> imSortList=ImmutableSortedSet.of("a", "b", "c", "a", "d", "b"); System.out.println("imSortList:"+imSortList); list.add("baby"); //关键看这里是否imlist也添加新元素了 System.out.println("list添加新元素之后看imlist:"+imlist); ImmutableSet<Color> imColorSet = ImmutableSet.<Color>builder() .add(new Color(0, 255, 255)) .add(new Color(0, 191, 255)) .build(); System.out.println("imColorSet:"+imColorSet); }
输出
imlist:[a, b, c]
imOflist:[peida, jerry, harry]
imSortList:[a, b, c, d]
list添加新元素之后看imlist:[a, b, c]
imColorSet:[java.awt.Color[r=0,g=255,b=255], java.awt.Color[r=0,g=191,b=255]]
智能的copyOf
copyOf方法比你想象的要智能,ImmutableXXX.copyOf会在合适的情况下避免拷贝元素的操作-先忽略具体的细节,但是它的实现一般都是很“智能”的。譬如:
@Test public void testCotyOf(){ ImmutableSet<String> imSet=ImmutableSet.of("peida","jerry","harry","lisa"); System.out.println("imSet:"+imSet); //set直接转list ImmutableList<String> imlist=ImmutableList.copyOf(imSet); System.out.println("imlist:"+imlist); //list直接转SortedSet ImmutableSortedSet<String> imSortSet=ImmutableSortedSet.copyOf(imSet); System.out.println("imSortSet:"+imSortSet); List<String> list=new ArrayList<String>(); for(int i=0;i<=10;i++){ list.add(i+"x"); } System.out.println("list:"+list); //截取集合部分元素 ImmutableList<String> imInfolist=ImmutableList.copyOf(list.subList(2, 8)); System.out.println("imInfolist:"+imInfolist); }
关联可变集合和不可变集合
可变集合接口 | 属于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 |
反倒是