GUAVA--集合(不可变集合)

一、为何要使用不可变集合

优势:java

  1. 当对象被不可信的库调用时,不可变形式是安全的;
  2. 不可变对象被多个线程调用时,不存在竞态条件问题;
  3. 不可变集合不须要考虑变化,所以能够节省时间和空间。全部不可变的集合都比它们的可变形式有更好的内存利用率;
  4. 不可变对象由于有固定不变,能够做为常量来安全使用。

建立对象的不可变拷贝是一项很好的防护性编程技巧。Guava 为全部 JDK 标准集合类型和 Guava 新集合类型 都提供了简单易用的不可变版本。编程

JDK 也提供了 Collections.unmodifiableXXX 方法把集合包装为不可变形式,但Guava认为不够好:安全

  • 笨重并且累赘:不能温馨地用在全部想作防护性拷贝的场景;
  • 不安全:要保证没人经过原集合的引用进行修改,返回的集合才是事实上不可变的;
  • 低效:包装过的集合仍然保有可变集合的开销,好比并发修改的检查、散列表的额外空间,等等。

若是你没有修改某个集合的需求,或者但愿某个集合保持不变时,把它防护性地拷贝到不可变集合是个很好的实 践。数据结构

重要提示:全部 Guava 不可变集合的实现都不接受 null 值。咱们对 Google 内部的代码库作过详细研究,发现 只有 5%的状况须要在集合中容许 null 元素,剩下的 95%场景都是遇到 null 值就快速失败。若是你须要在不可 变集合中使用 null,请使用 JDK 中的 Collections.unmodifiableXXX 方法。更多细节建议请参考“使用和避免 null”。并发

二、怎么使用不可变集合

2.一、建立不可变集合

// copyOf 方法,如 ImmutableSet.copyOf(set);
List<String> list = Arrays.asList("a", "b", "c");
ImmutableSet<String> strings = ImmutableSet.copyOf(list);

// of 方法,如 ImmutableSet.of(“a”, “b”, “c”)或 ImmutableMap.of(“a”, 1, “b”, 2);
ImmutableSet<String> of = ImmutableSet.of("a", "b", "c", "d", "e");

// Builder 工具
ImmutableSet<String> set = ImmutableSet.<String>builder()
	.add("a")
	.add("b")
	.add("c")
.build();

另外,对有序不可变集合来讲,排序是在构造集合的时候完成的,如:工具

ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");

会在构造时就把元素排序为 a, b, c, d。性能

2.二、更智能的 copyOf

ImmutableXXX.copyOf 方法会尝试在安全的时候避免作拷贝——实际的实现细节不详,但一般来讲是 很智能的,好比:ui

ImmutableSet<String> foobar = ImmutableSet.of("foo", "bar", "baz");
	thingamajig(foobar);
	void thingamajig(Collection<String> collection) {
	ImmutableList<String> defensiveCopy = ImmutableList.copyOf(collection);
	...
}

在这段代码中,ImmutableList.copyOf(foobar)会智能地直接返回 foobar.asList(),它是一个 ImmutableSet 的常量时间复杂度的 List 视图。google

做为一种探索,ImmutableXXX.copyOf(ImmutableCollection)会试图对以下状况避免线性时间拷贝:线程

  • 在常量时间内使用底层数据结构是可能的——例如,ImmutableSet.copyOf(ImmutableList)就不能在常量时间内完成。
  • 不会形成内存泄露——例如,你有个很大的不可变集合 ImmutableList hugeList, ImmutableList.copyOf(hugeList.subList(0, 10))就会显式地拷贝,以避免没必要要地持有 hugeList 的引用。
  • 不改变语义——因此 ImmutableSet.copyOf(myImmutableSortedSet)会显式地拷贝,由于和基于比较器的 ImmutableSortedSet 相比,ImmutableSet对hashCode()和 equals 有不一样语义。

在可能的状况下避免线性拷贝,能够最大限度地减小防护性编程风格所带来的性能开销。

2.三、asList视图

全部不可变集合都有一个 asList()方法提供 ImmutableList 视图,来帮助你用列表形式方便地读取集合元素。例 如,你可使用 sortedSet.asList().get(k)从 ImmutableSortedSet 中读取第 k 个最小元素。

asList()返回的 ImmutableList 一般是——并不老是——开销稳定的视图实现,而不是简单地把元素拷贝进 Lis t。也就是说,asList 返回的列表视图一般比通常的列表平均性能更好,好比,在底层集合支持的状况下,它老是 使用高效的 contains 方法。

2.四、关联可变集合和不可变集合

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

三、例子

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;

public class Guava {
	public static void main(String[] args) {
	//建立 3钟方式
        //一、of方法
        ImmutableList<String> immutableList = ImmutableList.of("1", "3", "2");
        System.out.println(immutableList);
        //二、copyOf方法
        ImmutableList<Object> immutableList1 = ImmutableList.copyOf(Lists.newArrayList(1, "abc", 3d));
        System.out.println(immutableList1);
        //三、builder构建
        ImmutableList<Integer> immutableList2 = ImmutableList.<Integer>builder().add(3).add(5).add(7).build();
        System.out.println(immutableList2);

        ImmutableSet<String> immutableSet = ImmutableSet.of("beibei", "jingjing", "huanhuan");
        System.out.println(immutableSet);
        //不可变集合均可以使用asList方法返回一个ImmutableList视图
        ImmutableList<String> immutableSetToList = immutableSet.asList();
        System.out.println(immutableSetToList);

        //会自动排序
        ImmutableSortedSet<String> immutableSortedSet = ImmutableSortedSet.of("1", "32", "3");
        System.out.println(immutableSortedSet);

        ImmutableMap<String, Integer> immutableMap = ImmutableMap.of("1", 11, "2", 22);
        System.out.println(immutableMap);
        System.out.println(immutableMap.asMultimap());
	}
}
输出结果:
[1, 3, 2]
[1, abc, 3.0]
[3, 5, 7]
[beibei, jingjing, huanhuan]
[beibei, jingjing, huanhuan]
[1, 3, 32]
{1=11, 2=22}
{1=[11], 2=[22]}

四、小结

Guava建立不可变集合的这些方法里,ImmutableList、ImmutableSet、ImmutableSortedSet都是继承了全部集合的父类Collection,建立出来的集合可使用JDK相对应集合的方法,是能够直接赋给JDK相对应集合的。其中ImmutableMap是实现Map接口的。

ImmutableList<String> immutableList = ImmutableList.of("1", "3", "2");
List<String> list = new ArrayList<String>();
list = immutableList;
immutableList.get(0);
相关文章
相关标签/搜索