qidao123.com技术社区-IT企服评测·应用市场

标题: 【Guava】集合工具类-Immutable&Lists&Maps&Sets [打印本页]

作者: 愛在花開的季節    时间: 2025-3-31 07:57
标题: 【Guava】集合工具类-Immutable&Lists&Maps&Sets
Immutable

《Effective Java》Item1)所述,在设计类的时候,倾向优先利用静态工厂方法(static factory method)而非构造函数(constructor)创建对象,长处在于:
同样,如《Effective Java》Item17所述,需要最小化可变性,ImmutableList遵照了最佳实践。首先,ImmutableList不可以通过构造函数实例化,更正确地说,不可以在package外部通过构造函数实例化。
而在步伐设计中利用不可变对象,也可以提高代码的可靠性和可维护性,其优势包罗:
创建对象的不可变拷贝是一项很好的防御性编程技巧。Guava为所有JDK标准集合类型和Guava新集合类型都提供了简单易用的不可变版本。JDK也提供了Collections.unmodifiableXXX方法把集合包装为不可变形式.
JDK不可变集合存在的问题

JDK 的 Collections 提供了 Unmodified Collections 不可变集合,但仅仅是通过装饰器模式提供了一个只读的视图,unmodifiableList自己是无法进行add等修改操作,但并没有阻止对原始集合的修改操作,所以说Collections.unmodifiableList实现的不是真正的不可变集合。
  1. List<String> list=new ArrayList<String>();
  2. list.add("a");
  3. list.add("b");
  4. list.add("c");
  5. //通过list创建一个不可变的unmodifiableList集合
  6. List<String> unmodifiableList = Collections.unmodifiableList(list);
  7. System.out.println(unmodifiableList);//[a,b,c]
  8. //通过list添加元素
  9. list.add("ddd");
  10. System.out.println("往list添加一个元素:" + list);//[a,b,c,ddd]
  11. System.out.println("通过list添加元素之后的unmodifiableList:" + unmodifiableList);[]//[a,b,c,ddd]
  12. //通过unmodifiableList添加元素
  13. unmodifiableList.add("eee");//报错
  14. System.out.println("往unmodifiableList添加一个元素:" + unmodifiableList);
复制代码
Guava不可变集合案例

而 Guava 提供的不可变集合不是原容器的视图,而是原容器的一份拷贝,因此更加简单高效,确保了真正的不可变性。
但是还要注意,由于immutable只是copy了元容器自己,并不是deep copy,因此对原容器的引用的内容进行修改,也会影响immutableXXX
注意:每个Guava immutable集合类的实现都拒绝null值。如果确实需要能接受null值的集合类,可以考虑用Collections.unmodifiableXXX。
immutable集合可以有以下几种方式来创建:
  1. List<String> list = new ArrayList<>();
  2. list.add("a");
  3. list.add("b");
  4. list.add("c");
  5. System.out.println("list:" + list);//[a, b, c]
  6. ImmutableList<String> imlist = ImmutableList.copyOf(list);
  7. System.out.println("imlist:" + imlist);//[a, b, c]
  8. ImmutableList<String> imOflist = ImmutableList.of("seven", "seven1", "seven2");
  9. System.out.println("imOflist:" + imOflist);//[seven, seven1, seven2]
  10. ImmutableSortedSet<String> imSortList = ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
  11. System.out.println("imSortList:" + imSortList);//[a, b, c, d]
  12. list.add("seven");
  13. System.out.println("list add a item after list:" + list);//[a, b, c, seven]
  14. System.out.println("list add a item after imlist:" + imlist);//[a, b, c]
  15. ImmutableSet<Color> imColorSet =
  16.        ImmutableSet.<Color>builder()
  17.              .add(new Color(0, 255, 255))
  18.              .add(new Color(0, 191, 255))
  19.              .build();
  20. System.out.println("imColorSet:" + imColorSet); //[java.awt.Color[r=0,g=255,b=255], java.awt.Color[r=0,g=191,b=255]]
复制代码
更智能的copyOf

ImmutableXXX.copyOf会在符合的情况下避免拷贝元素的操作。
  1. ImmutableSet<String> imSet = ImmutableSet.of("seven", "lisa", "seven1", "lisa1");
  2. System.out.println("imSet:" + imSet);//[seven, lisa, seven1, lisa1]
  3. ImmutableList<String> imlist = ImmutableList.copyOf(imSet);
  4. System.out.println("imlist:" + imlist);//[seven, lisa, seven1, lisa1]
  5. ImmutableSortedSet<String> imSortSet = ImmutableSortedSet.copyOf(imSet);
  6. System.out.println("imSortSet:" + imSortSet);//[lisa, lisa1, seven, seven1]
  7. List<String> list = new ArrayList<>();
  8. for (int i = 0; i < 20; i++) {
  9.        list.add(i + "x");
  10. }
  11. System.out.println("list:" + list);//[0x, 1x, 2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x, 15x, 16x, 17x, 18x, 19x]
  12. ImmutableList<String> imInfolist = ImmutableList.copyOf(list.subList(2, 18));
  13. System.out.println("imInfolist:" + imInfolist);//[2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x, 15x, 16x, 17x]
  14. int imInfolistSize = imInfolist.size();
  15. System.out.println("imInfolistSize:" + imInfolistSize);//16
  16. ImmutableSet<String> imInfoSet = ImmutableSet.copyOf(imInfolist.subList(2, imInfolistSize - 3));
  17. System.out.println("imInfoSet:" + imInfoSet);//[4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x]
复制代码
在这段代码中,ImmutableList.copyOf(imSet)会智能地直接返回 imSet.asList(),它是一个ImmutableSet的常量时间复杂度的List视图。
实际上,要实现copyOf方法,最简单的就是直接将底层的每个元素做深拷贝然后生成ImmutableList。但是对于所有情况都深拷贝的话,性能和存储开销必然比力大,那么源码里面是如何优化的呢?
所有不可变集合都有一个asList() 方法提供ImmutableList视图,让我们可以用列表形式方便地读取集合元素。例如,我们可以利用sortedSet.asList().get(k) 从 ImmutableSortedSet 中读取第k个最小元素。
asList()返回的ImmutableList 通常是(但并不总是)开销稳固的视图实现,而不是简单地把元素拷贝进List,也就是说,asList返回的列表视图通常比一般的列表平均性能更好,好比,在底层集合支持的情况下,它总是利用高效的contains方法。
源码如下:
  1. // com.google.common.collect.ImmutableList#copyOf(java.util.Collection<? extends E>)
  2. public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
  3.     //判断是否是不可变集合
  4.     if (elements instanceof ImmutableCollection) {
  5.         //如果传入的结合本身就是一个不可变集合,那么asList获取视图后返回;其实就是直接复用原来的collection
  6.         ImmutableList<E> list = ((ImmutableCollection)elements).asList();
  7.         //判断是否是要返回局部视图:是的话重新构建->调用Arrays.copyOf做深拷;不是的话就复用原来的
  8.         return list.isPartialView() ? asImmutableList(list.toArray()) : list;
  9.     } else {//如果不是,则执行construct方法:底层调用Arrays.copyOf做深拷贝
  10.         return construct(elements.toArray());
  11.     }
  12. }
  13. // com.google.common.collect.ImmutableCollection#asList
  14. public ImmutableList<E> asList() {
  15.     switch (this.size()) {
  16.         case 0:
  17.             // 返回一个空的不可变集合,这个空集合是个static final常量,可复用
  18.             return ImmutableList.of();
  19.         case 1:
  20.             // 返回一个不可变的 SingletonImmutableList 集合
  21.             return ImmutableList.of(this.iterator().next());
  22.         default:
  23.             return new RegularImmutableAsList(this, this.toArray());
  24.     }
  25. }
  26. //com.google.common.collect.RegularImmutableAsList#RegularImmutableAsList(com.google.common.collect.ImmutableCollection<E>, java.lang.Object[])
  27. RegularImmutableAsList(ImmutableCollection<E> delegate, Object[] array) {
  28.     this(delegate, ImmutableList.asImmutableList(array));
  29. }
  30. RegularImmutableAsList(ImmutableCollection<E> delegate, ImmutableList<? extends E> delegateList) {
  31.     this.delegate = delegate;
  32.     this.delegateList = delegateList;
  33. }
复制代码
以两个Set的并集作为视图
  1. private Lists() {
  2. }
复制代码
以两个Set的对称部分作为视图

[code]public static  Sets.SetView symmetricDifference(Set




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4