Immutable

如《Effective Java》Item1)所述,在设计类的时候,倾向优先使用静态工厂方法(static factory method)而非构造函数(constructor)创建对象,优点在于:

  1. 静态工厂方法多了一层名称信息,比构造函数更富表达性。

  2. 可以更灵活地创建对象,比如缓式初始化,缓存已创建对象。

  3. 静态方法内部返回的对象类型,可以是其声明类型的子类。

同样,如《Effective Java》Item17所述,需要最小化可变性,ImmutableList遵循了最佳实践。首先,ImmutableList不可以通过构造函数实例化,更准确地说,不可以在package外部通过构造函数实例化。

而在程序设计中使用不可变对象,也可以提高代码的可靠性和可维护性,其优势包括:

  1. 线程安全性(Thread Safety):不可变对象是线程安全的,无需同步操作,避免了竞态条件

  2. 安全性:可以防止在程序运行时被意外修改,提高了程序的安全性

  3. 易于理解和测试:不可变对象在创建后不会发生变化,更容易理解和测试

  4. 克隆和拷贝:不可变对象不需要实现可变对象的复制(Clone)和拷贝(Copy)逻辑,因为它们的状态不可变,克隆即是自己

创建对象的不可变拷贝是一项很好的防御性编程技巧。Guava为所有JDK标准集合类型和Guava新集合类型都提供了简单易用的不可变版本。JDK也提供了Collections.unmodifiableXXX方法把集合包装为不可变形式.

JDK不可变集合存在的问题

JDK 的 Collections 提供了 Unmodified Collections 不可变集合,但仅仅是通过装饰器模式提供了一个只读的视图,unmodifiableList本身是无法进行add等修改操作,但并没有阻止对原始集合的修改操作,所以说Collections.unmodifiableList实现的不是真正的不可变集合。

  • 笨重而且累赘:不能舒适地用在所有想做防御性拷贝的场景;

  • 不安全:要保证没人通过原集合的引用进行修改,返回的集合才是事实上不可变的;

  • 低效:包装过的集合仍然保有可变集合的开销,比如并发修改的检查、散列表的额外空间,等等。

Guava不可变集合案例

而 Guava 提供的不可变集合不是原容器的视图,而是原容器的一份拷贝,因此更加简单高效,确保了真正的不可变性。

但是还要注意,由于immutable只是copy了元容器本身,并不是deep copy,因此对原容器的引用的内容进行修改,也会影响immutableXXX

注意:每个Guava immutable集合类的实现都拒绝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类:减少中间对象的创建,提高内存使用效率。

更智能的copyOf

ImmutableXXX.copyOf会在合适的情况下避免拷贝元素的操作。

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

实际上,要实现copyOf方法,最简单的就是直接将底层的每个元素做深拷贝然后生成ImmutableList。但是对于所有情况都深拷贝的话,性能和存储开销必然比较大,那么源码里面是如何优化的呢?

所有不可变集合都有一个asList() 方法提供ImmutableList视图,让我们可以用列表形式方便地读取集合元素。例如,我们可以使用sortedSet.asList().get(k) 从 ImmutableSortedSet 中读取第k个最小元素。 asList()返回的ImmutableList 通常是(但并不总是)开销稳定的视图实现,而不是简单地把元素拷贝进List,也就是说,asList返回的列表视图通常比一般的列表平均性能更好,比如,在底层集合支持的情况下,它总是使用高效的contains方法。

源码如下:

实际上,ImmutableXXX.copyOf(ImmutableCollection)会试图对如下情况避免线性时间拷贝:

  • 在常量时间内使用底层数据结构是可能的:因为会获取视图后返回

  • 不会造成内存泄露:例如,有个很大的不可变集合ImmutableList<String> hugeListImmutableList.copyOf(hugeList.subList(0, 10))就会显式地拷贝(如上源码,会判断是否是局部视图),以免不必要地持有hugeList的引用。

  • 不改变语义:所以ImmutableSet.copyOf(myImmutableSortedSet)都会显式地拷贝,因为和基于比较器的ImmutableSortedSet相比,ImmutableSet对hashCode()和equals有不同语义。

在可能的情况下避免线性拷贝,可以最大限度地减少防御性编程风格所带来的性能开销。

Guava集合和不可变对应关系

可变集合类型****可变集合源:JDK or Guava?****Guava不可变集合CollectionJDKImmutableCollectionListJDKImmutableListSetJDKImmutableSetSortedSet/NavigableSetJDKImmutableSortedSetMapJDKImmutableMapSortedMapJDKImmutableSortedMapMultisetGuavaImmutableMultisetSortedMultisetGuavaImmutableSortedMultisetMultimapGuavaImmutableMultimapListMultimapGuavaImmutableListMultimapSetMultimapGuavaImmutableSetMultimapBiMapGuavaImmutableBiMapClassToInstanceMapGuavaImmutableClassToInstanceMapTableGuavaImmutableTable

Lists

私有的构造方法,可以看到这是一个真正的功能函数,下面对其函数进行分析

功能函数

首先根据每一个函数的更能进行了分类: 功能方法创建ArrayList方法1、newArrayList() 2、newArrayList(E… elements) 3、newArrayList(Iterable<? extends E> elements) 4、newArrayList(Iterator<? extends E> elements) 5、newArrayListWithCapacity(int initialArraySize) 6、newArrayListWithExpectedSize(int estimatedSize)创建LinkedList方法1、newLinkedList() 2、newLinkedList(Iterable<? extends E> elements)创建CopyOnWriteArrayList方法1、newCopyOnWriteArrayList() 2、newCopyOnWriteArrayList(Iterable<? extends E> elements)创建自制List规则1、asList(@Nullable E first, E[] rest) 2、asList(@Nullable E first, @Nullable E second, E[] rest)List笛卡尔乘积1、cartesianProduct(List<? extends List<? extends B>> lists) 2、cartesianProduct(List<? extends B>… lists)List变形transform(List<F> fromList, Function<? super F, ? extends T> function)分割list(作用之一:分页)partition(List<T> list, int size)将字符串作为字符数组进行操作1、charactersOf(String string) 2、charactersOf(CharSequence sequence)将list逆序reverse(List<T> list)

创建ArrayList方法

没有参数的创建ArrayList

传入一个数组,返回一个ArrayList

传入一个集合顶级接口,然后返回一个ArrayList

传入一个迭代器,返回一个ArrayList

传入想要的list长度,返回一个与传入值等长的ArrayList

传入一个想要的list长度,返回一个程序调优后的长度的ArrayList

创建LinkedList方法

不传入参数,直接返回一个LinkedList

传入一个容器,返回一个LinkedList

创建CopyOnWriteArrayList方法

不传入参数,直接返回一个新的CopyOnWriteArrayList

传入一个容器,返回一个CopyOnWriteArrayList,带有传入容器的值

创建自制List规则

使用案例:

这样做的一个好处是可以提高代码的可读性,因为它明确地区分了 “leader” 和 “members”,而不是将它们混在一起。而且,如果 “members” 是动态确定的(例如,它们来自另一个方法或计算结果),那么这个 asList 方法将比手动创建 List 并添加元素更为方便。

注意:asList返回的是视图,也就是说,原容器的变更会影响这些方法返回的容器内容

根据参数生成一个多一个参数的List

根据参数生成一个多两个个参数的List

List笛卡尔乘积

List变形

使用案例:

源码:

分割list(作用之一:分页)

这里的RandomAccessPartition是Partition的子类,且RandomAccessPartition对其的处理是直接调用了父类的方法,所以我们只需要解析Partition类就可以了

将字符串作为字符数组进行操作

主要用于将一个字符串转换为一个不可变的 List&lt;Character&gt;,使得字符串的字符可以像列表元素一样进行操作。

list逆序

实际上调用了ImmutableList类的reverse方法进行处理的逆序

Maps

私有的构造方法,可以看到这是一个真正的功能函数,下面对其函数进行分析

功能函数

功能方法创建EnumMap1、EnumMap<K, V> newEnumMap(Class<K> type) 2、EnumMap<K, V> newEnumMap(Map<K, ? extends V> map)返回不可变EnumMapImmutableMap<K, V> immutableEnumMap(Map<K, ? extends V> map)创建HashMap1、HashMap<K, V> newHashMap() 2、HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) 3、HashMap<K, V> newHashMap(Map<? extends K, ? extends V> map)创建LinkedHashMap1、LinkedHashMap<K, V> newLinkedHashMap() 2、LinkedHashMap<K, V> newLinkedHashMap(Map<? extends K, ? extends V> map)创建ConcurrentMapConcurrentMap<K, V> newConcurrentMap()创建TreeMap1、TreeMap<K, V> newTreeMap() 2、TreeMap<K, V> newTreeMap(SortedMap<K, ? extends V> map) 3、TreeMap<K, V> newTreeMap(@Nullable Comparator<C> comparator)创建IdentityHashMapIdentityHashMap<K, V> newIdentityHashMap()获取两个Map中不同元素的值1、MapDifference<K, V> difference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) 2、MapDifference<K, V> difference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right, Equivalence<? super V> valueEquivalence) 3、SortedMapDifference<K, V> difference(SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right)根据函数和set,构造Map1、Map<K, V> asMap(Set<K> set, Function<? super K, V> function) 2、SortedMap<K, V> asMap(SortedSet<K> set, Function<? super K, V> function) 3、NavigableMap<K, V> asMap(NavigableSet<K> set, Function<? super K, V> function)根据函数和迭代器,构造不可变的Map1、ImmutableMap<K, V> toMap(Iterator<K> keys, Function<? super K, V> valueFunction) 2、ImmutableMap<K, V> toMap(Iterator<K> keys, Function<? super K, V> valueFunction) 3、ImmutableMap<K, V> uniqueIndex(Iterable<V> values, Function<? super V, K> keyFunction) 4、ImmutableMap<K, V> uniqueIndex(Iterator<V> values, Function<? super V, K> keyFunction)从配置文件中读取数据,创建不可变的MapImmutableMap<String, String> fromProperties(Properties properties)返回Entry或Entry集合1、Entry<K, V> immutableEntry(@Nullable K key, @Nullable V value) 2、Set<Entry<K, V>> unmodifiableEntrySet(Set<Entry<K, V>> entrySet) 3、Entry<K, V> unmodifiableEntry(final Entry<? extends K, ? extends V> entry)返回特殊的BiMap类1、BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap) 2、BiMap<K, V> unmodifiableBiMap(BiMap<? extends K, ? extends V> bimap)根据Map和函数对Map进行转型1、Map<K, V2> transformValues(Map<K, V1> fromMap, Function<? super V1, V2> function) 2、SortedMap<K, V2> transformValues(SortedMap<K, V1> fromMap, Function<? super V1, V2> function) 3、NavigableMap<K, V2> transformValues(NavigableMap<K, V1> fromMap, Function<? super V1, V2> function) 4、Map<K, V2> transformEntries(Map<K, V1> fromMap, Maps.EntryTransformer<? super K, ? super V1, V2> transformer) 5、SortedMap<K, V2> transformEntries(SortedMap<K, V1> fromMap, Maps.EntryTransformer<? super K, ? super V1, V2> transformer) 6、NavigableMap<K, V2> transformEntries(NavigableMap<K, V1> fromMap, Maps.EntryTransformer<? super K, ? super V1, V2> transformer)使用函数进行过滤Map,然后返回同类型的Map分为4种过滤 一、针对Key进行过滤 1.Map<K, V> filterKeys(Map<K, V> unfiltered, Predicate<? super K> keyPredicate) 2.SortedMap<K, V> filterKeys(SortedMap<K, V> unfiltered, Predicate<? super K> keyPredicate) 3.NavigableMap<K, V> filterKeys(NavigableMap<K, V> unfiltered, Predicate<? super K> keyPredicate) 4.BiMap<K, V> filterKeys(BiMap<K, V> unfiltered, Predicate<? super K> keyPredicate) 二、针对Value进行过滤 1.Map<K, V> filterValues(Map<K, V> unfiltered, Predicate<? super V> valuePredicate) 2.SortedMap<K, V> filterValues(SortedMap<K, V> unfiltered, Predicate<? super V> valuePredicate) 3.NavigableMap<K, V> filterValues(NavigableMap<K, V> unfiltered, Predicate<? super V> valuePredicate) 4.BiMap<K, V> filterValues(BiMap<K, V> unfiltered, Predicate<? super V> valuePredicate) 三、针对Entry进行过滤 1.Map<K, V> filterEntries(Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) 2.SortedMap<K, V> filterEntries(SortedMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) 3.SortedMap<K, V> filterSortedIgnoreNavigable(SortedMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) 4.NavigableMap<K, V> filterEntries(NavigableMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) 5.BiMap<K, V> filterEntries(BiMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) 四、为含有过滤规则的Map进行过滤 1.Map<K, V> filterFiltered(Maps.AbstractFilteredMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate) 2.SortedMap<K, V> filterFiltered(Maps.FilteredEntrySortedMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate) 3.NavigableMap<K, V> filterFiltered(Maps.FilteredEntryNavigableMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate) 4.BiMap<K, V> filterFiltered(Maps.FilteredEntryBiMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate)

创建EnumMap

传入一个Class变量,返回一个EnumMap

传入一个Map变量,返回一个EnumMap

返回不可变EnumMap

传入一个Map,返回一个不可变的Map容器

创建HashMap

直接返回一个新的HashMap

返回一个有初始长度的HashMap

这里为什么是 0.75这个系数呢?

传入一个Map型变量,返回一个HashMap

创建LinkedHashMap

直接返回一个新的LinkedHashMap

传入一个Map变量,返回一个LinkedHashMap

创建ConcurrentMap

直接返回一个新的ConcurrentMap

创建TreeMap

直接返回一个新的TreeMap

传入一个Map变量,返回一个TreeMap,并将Map的值赋值给TreeMap

传入一个比较接口,返回一个根据传入的比较规则形成的TreeMap

创建IdentityHashMap

直接返回一个identityHashMap

IdentityHashMap与HashMap不同之处在于可以存入相同类的相同值,实际上他在put里的添加操作是不是使用equals而是用的==进行判断的

获取两个Map中不同元素的值

在说明Maps中这三个方法之前,先了解一下MapDifference接口和的实现类MapDifferenceImpl可以表现什么吧:

可以看到 MapDifferenceImpl 实现类中有4个变量

  • onlyOnLeft只存变量名为left的Map中独有的;

  • onlyOnRight只存变量名为right的Map中独有的;

  • onBoth存储两个map中共有的key并且value也相等的元素;

  • differences因为value存储的类型为ValueDifference,differences中存储的是共有的key并且value不同的元素

传入两个Map变量,根据left变量名的Map的类型进行判断交给哪个difference方法去处理

传入两个Map,使用doDifference方法将两个Map中的元素进行分类

传入一个SortedMap和一个Map变量,返回一个分类后的类

根据函数和set,构造Map

这个方法展示了如何将一个Set和一个Function 结合起来,创建一个视图(view),这个视图在每次查询时通过应用函数来动态生成键值对。

  1. 视图特性AsMapView创建的是一个视图,而不是一个独立的新集合。这意味着原始集合(Set)的任何修改都会反映在AsMapView中,反之亦然。这种行为类似于如何通过Collections.unmodifiableList()方法得到的不可修改的视图,但AsMapView是可修改的,其修改会影响到原始的集合。

  2. 延迟加载AsMapView在实际调用其get()方法之前不会计算键对应的值。这意味着如果你有一个非常昂贵的转换逻辑,它只有在实际需要该值时才会执行,这有助于提高效率。

  3. 用途:这个类非常适合创建动态计算的映射,其中映射的值是依赖于键的,并且可能不希望提前计算所有可能的值。例如,可以用它来根据需要生成配置设置、进行数据转换等。

  4. 实现:在内部,AsMapView使用了提供的SetFunction来实现Map接口。当调用get(Object key)时,如果key存在于集合中,则使用Function来计算值。

使用案例:

方法介绍:

传入一个set和一个规则,返回一个Map

传入一个SortedSet和一个规则,返回一个SortMap

传入一个NavigableSet和一个规则,返回一个NavigableMap

根据函数和迭代器,构造不可变的Map

此类方法传入的是一个容器的迭代器和一个规则,然后返回一个不可变的Map容器

传入一个key值容器和一个规则,直接交给重载函数去处理,返回一个不可变的Map容器

传入一个key值迭代器和一个规则返回一个不可变的map容器

根据value值容器和一个规则,直接交给重载函数去处理,返回一个不可变的Map容器

传入一个value值迭代器和一个规则返回一个不可变的map容器

从properties文件中读取数据,创建不可变的Map

从Properties获取的key和value,返回一个不可变的Map

返回Entry或Entry集合

传入一个key和一个value,返回一个不可变的Entry

返回特殊的BiMap类

Guava 提供了 BiMap 支持支持双向的映射关系,关于BiMap详情可以看后文

传入一个BiMap返回一个线程安全的BiMap

传入一个BiMap返回一个unmodifiableBiMap

根据Map和函数对Map进行转型

此类方法使用使用到了函数式编程,将一个Map的value作为新的Map的key,根据函数的规则计算出新的Map的Value,而这个转换只有在查看的时候才会做计算,而真正存储的是传入的map

传入一个Map和一个规则,返回一个有规则计算出来的Map

传入一个SortedMap和一个规则,返回一个由规则计算出来的新的Map

传入一个NavigableMap和一个规则,返回一个由规则计算出来的NavigableMap

传入一个Map和一个Maps规定的规则格式,根据规则返回一个新的Map

传入一个NavigableMap和一个Maps规定的规则格式,根据规则返回一个新的NavigableMap

使用函数进行过滤Map,然后返回同类型的Map

这里我们主要针对Key进行过滤的源码进行分析。当然Maps还提供了一些对Value、Entry、含有过滤器的Map进行过滤的方法。与上面过滤key的方法大体一样,都是继承了AbstractFilteredMap抽象类,实现了各自的过滤功能

使用keyPredicate函数接口制定过滤规则,对Map进行过滤,对于Map中Key进行过滤的类FilteredKeyMap源码如下:

传入一个Map和过滤他的规则,返回一个新的Map

传入一个SortedMap,然后交给filterEntries方法进行处理

传入一个NavigableMap,然后交给filterEntries方法进行处理

传入一个BiMap,然后交给filterEntries方法进行处理

Sets

功能函数

功能方法创建不可变的set1、ImmutableSet<E> immutableEnumSet(E anElement, E… otherElements) 2、ImmutableSet<E> immutableEnumSet(Iterable<E> elements)创建HashSet1、HashSet<E> newHashSet() 2、HashSet<E> newHashSet(E… elements) 3、HashSet<E> newHashSetWithExpectedSize(int expectedSize) 4、HashSet<E> newHashSet(Iterable<? extends E> elements) 5、HashSet<E> newHashSet(Iterator<? extends E> elements)创建线程安全的Set1、Set<E> newConcurrentHashSet() 2、Set<E> newConcurrentHashSet(Iterable<? extends E> elements)创建LinkedHashMap1、LinkedHashSet<E> newLinkedHashSet() 2、LinkedHashSet<E> newLinkedHashSetWithExpectedSize(int expectedSize) 3、LinkedHashSet<E> newLinkedHashSet(Iterable<? extends E> elements)创建TreeSet1、TreeSet<E> newTreeSet() 2、TreeSet<E> newTreeSet(Iterable<? extends E> elements) 3、TreeSet<E> newTreeSet(Comparator<? super E> comparator)创建IdentityHashSetSet<E> newIdentityHashSet()创建CopyOnWriteArraySet1、CopyOnWriteArraySet<E> newCopyOnWriteArraySet() 2、CopyOnWriteArraySet<E> newCopyOnWriteArraySet(Iterable<? extends E> elements)创建EnumSet1、EnumSet<E> newEnumSet(Iterable<E> iterable, Class<E> elementType) 2、EnumSet<E> complementOf(Collection<E> collection) 3、EnumSet<E> complementOf(Collection<E> collection, Class<E> type) 4、EnumSet<E> makeComplementByHand(Collection<E> collection, Class<E> type)根据Map创建一个SetSet<E> newSetFromMap(Map<E, Boolean> map)以两个Set的并集作为视图Sets.SetView<E> union(final Set<? extends E> set1, final Set<? extends E> set2)以两个Set的交集作为视图Sets.SetView<E> intersection(final Set<E> set1, final Set<?> set2)以两个Set的互不重叠的部分作为视图Sets.SetView<E> difference(final Set<E> set1, final Set<?> set2)以两个Set的对称部分作为视图Sets.SetView<E> symmetricDifference(Set<? extends E> set1, Set<? extends E> set2)过滤Set1、filter(Set<E> unfiltered, Predicate<? super E> predicate) 2、SortedSet<E> filter(SortedSet<E> unfiltered, Predicate<? super E> predicate) 3、SortedSet<E> filterSortedIgnoreNavigable(SortedSet<E> unfiltered, Predicate<? super E> predicate) 4、NavigableSet<E> filter(NavigableSet<E> unfiltered, Predicate<? super E> predicate)获取两个Set集合的笛卡尔积1、Set<List<B>> cartesianProduct(List<? extends Set<? extends B>> sets) 2、Set<List<B>> cartesianProduct(Set<? extends B>… sets)

创建不可变的Set

根据传入的参数,创建一个不可变的Set

根据一个集合创建一个不可变的Set

创建HashSet

直接new一个HashSet

传入一个数组,返回一个HashSet

创建一个期望大小的HashSet

根据传入的集合创建一个HashSet

根据传入的迭代器创建一个HashSet

创建线程安全的Set

使用ConcurrentHashMap创建一个Set

使用传入的集合创建一个线程安全的Set

创建LinkedHashSet

直接创建一个LinkedHashSet

创建一个期望大小的LinkedHashSet

根据传入的集合,返回一个LinkedHashSet

创建TreeSet

直接创建一个TreeSet

传入一个集合,返回一个TreeSet,并将集合中的元素赋值给TreeSet

传入一个Comparator,根据Comparator的规则创建一个TreeSet

创建IdentityHashSet

根据Maps.newIdentityHashMap()和Sets.newSetFromMap两个方法创建一个IdentityHashSet

创建CopyOnWriteArraySet

直接创建一个CopyOnWriteArraySet

根据传入的集合创建一个CopyOnWriteArraySet,并将集合中的数据赋值给CopyOnWriteArraySet

创建EnumSet

根据传入的集合和一个类型,返回一个EnumSet

传入一个集合,返回一个EnumSet

根据一个Map创建一个Set

根据Map创建一个Set

以两个Set的互不重叠的部分作为视图

传入两个Set,返回一个两个set1中不包含set2中的元素

以两个Set的并集作为视图

以两个Set的交集作为视图

以两个Set的对称部分作为视图

过滤Set

Set的过滤和Maps中实现的各种过滤都是大同小异。

传入一个Set和一个过滤规则,返回一个过滤后的Set: