【Guava】集合工具类-ImmutableListsMapsSets

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实现的不是真正的不可变集合。

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);//[a,b,c]//通过list添加元素
list.add("ddd");
System.out.println("往list添加一个元素:" + list);//[a,b,c,ddd]
System.out.println("通过list添加元素之后的unmodifiableList:" + unmodifiableList);[]//[a,b,c,ddd]//通过unmodifiableList添加元素
unmodifiableList.add("eee");//报错
System.out.println("往unmodifiableList添加一个元素:" + 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类:减少中间对象的创建,提高内存使用效率。
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
System.out.println("list:" + list);//[a, b, c]ImmutableList<String> imlist = ImmutableList.copyOf(list);
System.out.println("imlist:" + imlist);//[a, b, c]ImmutableList<String> imOflist = ImmutableList.of("seven", "seven1", "seven2");
System.out.println("imOflist:" + imOflist);//[seven, seven1, seven2]ImmutableSortedSet<String> imSortList = ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
System.out.println("imSortList:" + imSortList);//[a, b, c, d]list.add("seven");
System.out.println("list add a item after list:" + list);//[a, b, c, seven]
System.out.println("list add a item after imlist:" + imlist);//[a, b, c]ImmutableSet<Color> imColorSet =ImmutableSet.<Color>builder().add(new Color(0, 255, 255)).add(new Color(0, 191, 255)).build();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会在合适的情况下避免拷贝元素的操作。

ImmutableSet<String> imSet = ImmutableSet.of("seven", "lisa", "seven1", "lisa1");
System.out.println("imSet:" + imSet);//[seven, lisa, seven1, lisa1]
ImmutableList<String> imlist = ImmutableList.copyOf(imSet);
System.out.println("imlist:" + imlist);//[seven, lisa, seven1, lisa1]
ImmutableSortedSet<String> imSortSet = ImmutableSortedSet.copyOf(imSet);
System.out.println("imSortSet:" + imSortSet);//[lisa, lisa1, seven, seven1]List<String> list = new ArrayList<>();
for (int i = 0; i < 20; i++) {list.add(i + "x");}
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]
ImmutableList<String> imInfolist = ImmutableList.copyOf(list.subList(2, 18));
System.out.println("imInfolist:" + imInfolist);//[2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x, 15x, 16x, 17x]
int imInfolistSize = imInfolist.size();
System.out.println("imInfolistSize:" + imInfolistSize);//16
ImmutableSet<String> imInfoSet = ImmutableSet.copyOf(imInfolist.subList(2, imInfolistSize - 3));
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方法。

源码如下:

// com.google.common.collect.ImmutableList#copyOf(java.util.Collection<? extends E>)
public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {//判断是否是不可变集合if (elements instanceof ImmutableCollection) {//如果传入的结合本身就是一个不可变集合,那么asList获取视图后返回;其实就是直接复用原来的collectionImmutableList<E> list = ((ImmutableCollection)elements).asList();//判断是否是要返回局部视图:是的话重新构建->调用Arrays.copyOf做深拷;不是的话就复用原来的return list.isPartialView() ? asImmutableList(list.toArray()) : list;} else {//如果不是,则执行construct方法:底层调用Arrays.copyOf做深拷贝return construct(elements.toArray());}
}// com.google.common.collect.ImmutableCollection#asList
public ImmutableList<E> asList() {switch (this.size()) {case 0:// 返回一个空的不可变集合,这个空集合是个static final常量,可复用return ImmutableList.of();case 1:// 返回一个不可变的 SingletonImmutableList 集合return ImmutableList.of(this.iterator().next());default:return new RegularImmutableAsList(this, this.toArray());}
}//com.google.common.collect.RegularImmutableAsList#RegularImmutableAsList(com.google.common.collect.ImmutableCollection<E>, java.lang.Object[])
RegularImmutableAsList(ImmutableCollection<E> delegate, Object[] array) {this(delegate, ImmutableList.asImmutableList(array));
}
RegularImmutableAsList(ImmutableCollection<E> delegate, ImmutableList<? extends E> delegateList) {this.delegate = delegate;this.delegateList = delegateList;
}

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

  • 在常量时间内使用底层数据结构是可能的:因为会获取视图后返回
  • 不会造成内存泄露:例如,有个很大的不可变集合ImmutableList<String> hugeListImmutableList.copyOf(hugeList.subList(0, 10))就会显式地拷贝(如上源码,会判断是否是局部视图),以免不必要地持有hugeList的引用。
  • 不改变语义:所以ImmutableSet.copyOf(myImmutableSortedSet)都会显式地拷贝,因为和基于比较器的ImmutableSortedSet相比,ImmutableSet对hashCode()和equals有不同语义。

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

Guava集合和不可变对应关系

可变集合类型 可变集合源:JDK or Guava? 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

Lists

private 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方法

  1. 没有参数的创建ArrayList

    public static <E> ArrayList<E> newArrayList() {return new ArrayList();//直接返回一个新的ArrayList容器
    }
    
  2. 传入一个数组,返回一个ArrayList

    public static <E> ArrayList<E> newArrayList(E... elements) {//对数组进行判空处理Preconditions.checkNotNull(elements);// computeArrayListCapacity对当前数量进行优化int capacity = computeArrayListCapacity(elements.length);//这里根据优化后的数量进行创建一个新的ArrayListArrayList list = new ArrayList(capacity);//将数组里面的元素都存储在List中Collections.addAll(list, elements);return list;
    }//目的是为了给定一个期望的元素数量(arraySize),计算出为了避免或减少动态扩容带来的开销,列表初始化时应该分配的容量
    @VisibleForTesting
    static int computeArrayListCapacity(int arraySize) {//确保arraySize非负数CollectPreconditions.checkNonnegative(arraySize, "arraySize");//确保最后的数值在 int范围内return Ints.saturatedCast(5L + (long)arraySize + (long)(arraySize / 10));
    }
    
  3. 传入一个集合顶级接口,然后返回一个ArrayList

    public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {//对集合进行判空Preconditions.checkNotNull(elements);//根据传入的实际类型,进行分别处理return elements instanceof Collection ? new ArrayList(Collections2.cast(elements)):newArrayList((Iterator)elements.
    iterator());
    }
    
  4. 传入一个迭代器,返回一个ArrayList

    public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {ArrayList list = newArrayList();//根据Iterators中的addAll方法将迭代器中的源码装入list集合中Iterators.addAll(list, elements);return list;
    }
    
  5. 传入想要的list长度,返回一个与传入值等长的ArrayList

    //直接返回一个新的ArrayList,并且长度为传入的长度
    public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize) {CollectPreconditions.checkNonnegative(initialArraySize, "initialArraySize");return new ArrayList(initialArraySize);
    }
    
  6. 传入一个想要的list长度,返回一个程序调优后的长度的ArrayList

    public static <E> ArrayList<E> newArrayListWithExpectedSize(int estimatedSize) {return new ArrayList(computeArrayListCapacity(estimatedSize));//返回一个长度调优后的ArrayList
    }
    

创建LinkedList方法

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

    public static <E> LinkedList<E> newLinkedList() {return new LinkedList();//直接返回一个LinkedList
    }
    
  2. 传入一个容器,返回一个LinkedList

    public static <E> LinkedList<E> newLinkedList(Iterable<? extends E> elements) {LinkedList list = newLinkedList();//将传入的容器,使用Iterables的addAll方法进行的数据转移Iterables.addAll(list, elements);return list;
    }
    

创建CopyOnWriteArrayList方法

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

    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList() {return new CopyOnWriteArrayList();//直接返回一个新的CopyOnWriteArrayList
    }
    
  2. 传入一个容器,返回一个CopyOnWriteArrayList,带有传入容器的值

    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList(Iterable<? extends E> elements) {Object elementsCollection = elements instanceof Collection?Collections2.cast(elements):newArrayList((Iterable)elements);return new CopyOnWriteArrayList((Collection)elementsCollection);
    }
    

创建自制List规则

使用案例:

String leader = "leader";
String[] members = {"member1", "member2", "member3"};List<String> group = Lists.asList(leader, members);
System.out.println(group);

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

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

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

    public static <E> List<E> asList(@Nullable E first, E[] rest) {return new Lists.OnePlusArrayList(first, rest);//返回一个Lists中的内部类OnePlusArrayList
    }private static class OnePlusArrayList<E> extends AbstractList<E> implements Serializable, RandomAccess {final E first;final E[] rest;private static final long serialVersionUID = 0L;OnePlusArrayList(@Nullable E first, E[] rest) {this.first = first;this.rest = (Object[])Preconditions.checkNotNull(rest);}// 重写了size和get方法// 因为是比原来数组多1个数,所以size方法在原来的基础上进行了+1操作。public int size() {return this.rest.length + 1;}//对get的重写是将所有的下标逻辑上后移了一位。public E get(int index) {Preconditions.checkElementIndex(index, this.size());return index == 0 ? this.first:this.rest[index - 1];}
    }
    
  2. 根据参数生成一个多两个个参数的List

    public static <E> List<E> asList(@Nullable E first, @Nullable E second, E[] rest) {return new Lists.TwoPlusArrayList(first, second, rest);//返回一个Lists中的内部类TwoPlusArrayList
    }private static class TwoPlusArrayList<E> extends AbstractList<E> implements Serializable, RandomAccess {final E first;final E second;final E[] rest;private static final long serialVersionUID = 0L;TwoPlusArrayList(@Nullable E first, @Nullable E second, E[] rest) {this.first = first;this.second = second;this.rest = (Object[])Preconditions.checkNotNull(rest);}// 重写了size和get两个方法,size在实际数组长度上进行了+2的操作public int size() {return this.rest.length + 2;}//get则在逻辑上将下标进行了后移两位public E get(int index) {switch(index) {case 0:return this.first;case 1:return this.second;default:Preconditions.checkElementIndex(index, this.size());return this.rest[index - 2];}}
    } 
    

List笛卡尔乘积

public static <B> List<List<B>> cartesianProduct(List<? extends List<? extends B>> lists) {return CartesianList.create(lists);
}//整个方法的逻辑是将输入的一组列表转换成一个表示它们所有可能组合(笛卡尔积)的列表结构,同时确保输入列表的不可变性。
//这种方法在需要处理多维数据组合时特别有用,例如在配置管理、测试用例生成等应用场景中。
static <E> List<List<E>> create(List<? extends List<? extends E>> lists) {ImmutableList.Builder<List<E>> axesBuilder = new ImmutableList.Builder(lists.size());Iterator var2 = lists.iterator();while(var2.hasNext()) {List<? extends E> list = (List)var2.next();List<E> copy = ImmutableList.copyOf(list);if (copy.isEmpty()) {//如果任意一个子列表为空,则整个笛卡尔积列表也应为空(因为任何东西与空集的笛卡尔积都是空集),因此直接返回一个空的不可变列表。return ImmutableList.of();}axesBuilder.add(copy);}return new CartesianList(axesBuilder.build());
}

List变形

使用案例:

List<String> stringList = Arrays.asList("1", "2", "3");
List<Integer> integerList = transform(stringList, s -> Integer.parseInt(s));

源码:

public static <F, T> List<T> transform(List<F> fromList, Function<? super F, ? extends T> function) {//依据 fromList 是否支持随机访问(例如 ArrayList),来决定使用哪种内部实现方式,以提高效率。//不过无论使用哪种方式进行处理,在他们的实现类中都重写了listIterator方法return (List)(fromList instanceof RandomAccess?new Lists.TransformingRandomAccessList(fromList, function):new Lists.TransformingSequentialList(fromList, function));
}private static class TransformingRandomAccessList<F, T> extends AbstractList<T> implements RandomAccess, Serializable {final List<F> fromList;final Function<? super F, ? extends T> function;private static final long serialVersionUID = 0L;TransformingRandomAccessList(List<F> fromList, Function<? super F, ? extends T> function) {this.fromList = (List)Preconditions.checkNotNull(fromList);this.function = (Function)Preconditions.checkNotNull(function);}public ListIterator<T> listIterator(int index) {//当通过 listIterator 方法获取迭代器时,实际上是获取了原始列表 fromList 的迭代器,并将其包装在 TransformedListIterator 中。//每次迭代时,TransformedListIterator 会调用 transform 方法,该方法使用 function 将原始列表中的元素转换为目标类型 T。return new TransformedListIterator(this.fromList.listIterator(index)) {T transform(F from) {return TransformingRandomAccessList.this.function.apply(from);}};}
}

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

// 程序根据传入的List进行分类处理
public static <T> List<List<T>> partition(List<T> list, int size) {Preconditions.checkNotNull(list);Preconditions.checkArgument(size > 0);return (List)(list instanceof RandomAccess?new Lists.RandomAccessPartition(list, size):new Lists.Partition(list, size));
}

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

private static class Partition<T> extends AbstractList<List<T>> {final List<T> list;final int size;Partition(List<T> list, int size) {this.list = list;this.size = size;}//get方法进行了截取操作,而它的截取底层是subList实现的。它所get的下标为第几组Listpublic List<T> get(int index) {Preconditions.checkElementIndex(index, this.size());int start = index * this.size;int end = Math.min(start + this.size, this.list.size());return this.list.subList(start, end);}public int size() {return IntMath.divide(this.list.size(), this.size, RoundingMode.CEILING);}public boolean isEmpty() {return this.list.isEmpty();}
}

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

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

//两个方法分别接收字符串和CharSequence作为参数,将参数传入CharSequenceAsList类中进行处理:
public static ImmutableList<Character> charactersOf(String string) {return new Lists.StringAsImmutableList((String)Preconditions.checkNotNull(string));
}
public static List<Character> charactersOf(CharSequence sequence) {return new Lists.CharSequenceAsList((CharSequence)Preconditions.checkNotNull(sequence));
}
//实际上就是对间接使用String类中的方法进行处理字符串
private static final class StringAsImmutableList extends ImmutableList<Character> {private final String string;StringAsImmutableList(String string) {this.string = string;}public int indexOf(@Nullable Object object) {return object instanceof Character?this.string.indexOf(((Character)object).charValue()):-1;}public int lastIndexOf(@Nullable Object object) {return object instanceof Character?this.string.lastIndexOf(((Character)object).charValue()):-1;}public ImmutableList<Character> subList(int fromIndex, int toIndex) {Preconditions.checkPositionIndexes(fromIndex, toIndex, this.size());return Lists.charactersOf((String)this.string.substring(fromIndex, toIndex));}boolean isPartialView() {return false;}public Character get(int index) {Preconditions.checkElementIndex(index, this.size());return Character.valueOf(this.string.charAt(index));}public int size() {return this.string.length();}
}

list逆序

public static <T> List<T> reverse(List<T> list) {if (list instanceof ImmutableList) {List<?> reversed = ((ImmutableList)list).reverse();List<T> result = reversed;return result;} else if (list instanceof ReverseList) {return ((ReverseList)list).getForwardList();} else {return (List)(list instanceof RandomAccess ? new RandomAccessReverseList(list) : new ReverseList(list));}
}

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

Maps

private Maps() {
}

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

功能函数

功能 方法
创建EnumMap 1、EnumMap<K, V> newEnumMap(Class<K> type)
2、EnumMap<K, V> newEnumMap(Map<K, ? extends V> map)
返回不可变EnumMap ImmutableMap<K, V> immutableEnumMap(Map<K, ? extends V> map)
创建HashMap 1、HashMap<K, V> newHashMap()
2、HashMap<K, V> newHashMapWithExpectedSize(int expectedSize)
3、HashMap<K, V> newHashMap(Map<? extends K, ? extends V> map)
创建LinkedHashMap 1、LinkedHashMap<K, V> newLinkedHashMap()
2、LinkedHashMap<K, V> newLinkedHashMap(Map<? extends K, ? extends V> map)
创建ConcurrentMap ConcurrentMap<K, V> newConcurrentMap()
创建TreeMap 1、TreeMap<K, V> newTreeMap()
2、TreeMap<K, V> newTreeMap(SortedMap<K, ? extends V> map)
3、TreeMap<K, V> newTreeMap(@Nullable Comparator<C> comparator)
创建IdentityHashMap IdentityHashMap<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,构造Map 1、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)
根据函数和迭代器,构造不可变的Map 1、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)
从配置文件中读取数据,创建不可变的Map ImmutableMap<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

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

    public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Class<K> type) {return new EnumMap((Class)Preconditions.checkNotNull(type));
    }
    
  2. 传入一个Map变量,返回一个EnumMap

    public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Map<K, ? extends V> map) {return new EnumMap(map);
    }//java.util.EnumMap#EnumMap(java.util.Map<K,? extends V>)
    public EnumMap(Map<K, ? extends V> m) {if (m instanceof EnumMap) {EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;keyType = em.keyType;keyUniverse = em.keyUniverse;vals = em.vals.clone();size = em.size;} else {if (m.isEmpty())throw new IllegalArgumentException("Specified map is empty");keyType = m.keySet().iterator().next().getDeclaringClass();keyUniverse = getKeyUniverse(keyType);vals = new Object[keyUniverse.length];//对于传入的Map赋值给新的EnumMap步骤就由EnumMap的putAll方法进行操作了。putAll(m);}
    }
    

返回不可变EnumMap

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

public static <K extends Enum<K>, V> ImmutableMap<K, V> immutableEnumMap(Map<K, ? extends V> map) {if(map instanceof ImmutableEnumMap) {//如果map为ImmutableEnumMap类型,直接强转为ImmutableEnumMap类型的容器ImmutableEnumMap<K, V> result = (ImmutableEnumMap)map;return result;} else  {Iterator<? extends Map.Entry<K, ? extends V>> entryItr = map.entrySet().iterator();if (!entryItr.hasNext()) {//如果map为空,则直接返回新建的空的ImmutableMap容器return ImmutableMap.of();} else {Map.Entry<K, ? extends V> entry1 = (Map.Entry)entryItr.next();K key1 = (Enum)entry1.getKey();V value1 = entry1.getValue();CollectPreconditions.checkEntryNotNull(key1, value1);Class<K> clazz = key1.getDeclaringClass();EnumMap<K, V> enumMap = new EnumMap(clazz);enumMap.put(key1, value1);while(entryItr.hasNext()) {Map.Entry<K, ? extends V> entry = (Map.Entry)entryItr.next();K key = (Enum)entry.getKey();V value = entry.getValue();//key和value都不能为nullCollectPreconditions.checkEntryNotNull(key, value);enumMap.put(key, value);}//以上成立,则直接使用ImmutableEnumMap中函数为map进行转换return ImmutableEnumMap.asImmutable(enumMap);}}
}

创建HashMap

  1. 直接返回一个新的HashMap

    public static <K, V> HashMap<K, V> newHashMap() {return new HashMap();
    }
    
  2. 返回一个有初始长度的HashMap

    public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {return new HashMap(capacity(expectedSize));
    }//根据传入的长度,返回一个实际可用expectedSize的HashMap,capacity方法就是计算实际长度的一个方法
    static int capacity(int expectedSize) {if(expectedSize < 3) {CollectPreconditions.checkNonnegative(expectedSize, "expectedSize");return expectedSize + 1;} else {// 假设传入的是8,返回的就是8/0.75 + 1 = 11,根据HashMap的原则,会扩容成16。所以这里考虑的是什么?为什么这么设置return expectedSize < 1073741824 ? (int)((float)expectedSize / 0.75F + 1.0F) : Integer.MAX_VALUE;}
    }
    

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

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

    public static <K, V> HashMap<K, V> newHashMap(Map<? extends K, ? extends V> map) {return new HashMap(map);//这个步骤就由HashMap的putMapEntries方法进行操作了
    }
    

创建LinkedHashMap

  1. 直接返回一个新的LinkedHashMap

    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() {return new LinkedHashMap();
    }
    
  2. 传入一个Map变量,返回一个LinkedHashMap

    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(Map<? extends K, ? extends V> map) {return new LinkedHashMap(map);//这个步骤就由LinkedHashMap的putMapEntries方法进行操作了。
    }
    

创建ConcurrentMap

直接返回一个新的ConcurrentMap

public static <K, V> ConcurrentMap<K, V> newConcurrentMap() {return new ConcurrentHashMap();
}

创建TreeMap

  1. 直接返回一个新的TreeMap

    public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() {return new TreeMap();
    }
    
  2. 传入一个Map变量,返回一个TreeMap,并将Map的值赋值给TreeMap

    public static <K, V> TreeMap<K, V> newTreeMap(SortedMap<K, ? extends V> map) {return new TreeMap(map);
    }
    
  3. 传入一个比较接口,返回一个根据传入的比较规则形成的TreeMap

    public static <C, K extends C, V> TreeMap<K, V> newTreeMap(@Nullable Comparator<C> comparator) {return new TreeMap(comparator);
    }
    

创建IdentityHashMap

直接返回一个identityHashMap

public static <K, V> IdentityHashMap<K, V> newIdentityHashMap() {return new IdentityHashMap();
}

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

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

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

public interface MapDifference<K, V> {boolean areEqual();Map<K, V> entriesOnlyOnLeft();Map<K, V> entriesOnlyOnRight();Map<K, V> entriesInCommon();Map<K, ValueDifference<V>> entriesDiffering();boolean equals(@CheckForNull Object var1);int hashCode();@DoNotMock("Use Maps.difference")public interface ValueDifference<V> {@ParametricNullnessV leftValue();@ParametricNullnessV rightValue();boolean equals(@CheckForNull Object var1);int hashCode();}
}static class MapDifferenceImpl<K, V> implements MapDifference<K, V> {final Map<K, V> onlyOnLeft;final Map<K, V> onlyOnRight;final Map<K, V> onBoth;final Map<K, ValueDifference<V>> differences;MapDifferenceImpl(Map<K, V> onlyOnLeft, Map<K, V> onlyOnRight, Map<K, V> onBoth, Map<K, ValueDifference<V>> differences) {this.onlyOnLeft = Maps.unmodifiableMap(onlyOnLeft);this.onlyOnRight = Maps.unmodifiableMap(onlyOnRight);this.onBoth = Maps.unmodifiableMap(onBoth);this.differences = Maps.unmodifiableMap(differences);}public boolean areEqual() {return this.onlyOnLeft.isEmpty() && this.onlyOnRight.isEmpty() && this.differences.isEmpty();}public Map<K, V> entriesOnlyOnLeft() {return this.onlyOnLeft; }public Map<K, V> entriesOnlyOnRight() {return this.onlyOnRight; }public Map<K, V> entriesInCommon() {return this.onBoth; }public Map<K, ValueDifference<V>> entriesDiffering() { return this.differences; }//equals等其它方法...
}

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

  • onlyOnLeft只存变量名为left的Map中独有的;
  • onlyOnRight只存变量名为right的Map中独有的;
  • onBoth存储两个map中共有的key并且value也相等的元素;
  • differences因为value存储的类型为ValueDifference,differences中存储的是共有的key并且value不同的元素
  1. 传入两个Map变量,根据left变量名的Map的类型进行判断交给哪个difference方法去处理

    public static <K, V> MapDifference<K, V> difference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) {if(left instanceof SortedMap) {SortedMap<K, ? extends V> sortedLeft = (SortedMap)left;return difference(sortedLeft, right);} else {MapDifference<K, V> result = difference(left, right, Equivalence.equals());return result;}
    }
    
  2. 传入两个Map,使用doDifference方法将两个Map中的元素进行分类

    public static <K, V> MapDifference<K, V> difference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right, Equivalence<? super V> valueEquivalence) {Preconditions.checkNotNull(valueEquivalence);HashMap onlyOnLeft = newHashMap();HashMap onlyOnRight = new HashMap(right);HashMap onBoth = newHashMap();Map<K, MapDifference.ValueDifference<V>> differences = newLinkedHashMap();doDifference(left, right, valueEquivalence, onlyOnLeft, onlyOnRight, onBoth, differences);return new Maps.MapDifferenceImpl(onlyOnLeft, onlyOnRight, onBoth, differences);
    }private static <K, V> void doDifference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right, Equivalence<? super V> valueEquivalence, Map<K, V> onlyOnLeft, Map<K, V> onlyOnRight, Map<K, V> onBoth, Map<K, MapDifference.ValueDifference<V>> differences) {Iterator var7 = left.entrySet().iterator();//对left进行遍历操作while(var7.hasNext()) {Map.Entry<? extends K, ? extends V> entry = (Map.Entry)var7.next();K leftKey = entry.getKey();V leftValue = entry.getValue();//查看right中是否包括这个key值if (right.containsKey(leftKey)) {//如果right中也包括这个key值,则将这个值在right中去除V rightValue = NullnessCasts.uncheckedCastNullableTToT(onlyOnRight.remove(leftKey));//判断这个key值的left和right的value值是否相等if (valueEquivalence.equivalent(leftValue, rightValue)) {//如果两个value值相等,将其填入onBoth的Map容器中onBoth.put(leftKey, leftValue);} else {//如果两个value值不相等,将其填入differences的Map容器中differences.put(leftKey, Maps.ValueDifferenceImpl.create(leftValue, rightValue));}} else {//如果这个key在right中不存在,则将其填入onlyOnLeft容器中onlyOnLeft.put(leftKey, leftValue);}}
    }
    
  3. 传入一个SortedMap和一个Map变量,返回一个分类后的类

    public static <K, V> SortedMapDifference<K, V> difference(SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {Preconditions.checkNotNull(left);Preconditions.checkNotNull(right);Comparator<? super K> comparator = orNaturalOrder(left.comparator());SortedMap<K, V> onlyOnLeft = newTreeMap(comparator);SortedMap<K, V> onlyOnRight = newTreeMap(comparator);onlyOnRight.putAll(right);SortedMap<K, V> onBoth = newTreeMap(comparator);SortedMap<K, MapDifference.ValueDifference<V>> differences = newTreeMap(comparator);doDifference(left, right, Equivalence.equals(), onlyOnLeft, onlyOnRight, onBoth, differences);return new SortedMapDifferenceImpl(onlyOnLeft, onlyOnRight, onBoth, differences);
    }
    

根据函数和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来计算值。

使用案例:

//假设有一组产品ID,需要根据产品ID动态获取产品价格。价格计算可能依赖于多种因素,如商品的实时供需状况、促销活动等,这些都可以通过一个函数来实现:
Set<Integer> productIds = new HashSet<>();
productIds.add(1);
productIds.add(2);Function<Integer, Double> priceFunction = productId -> {// 假设这里进行一些复杂的计算来决定价格return productId * 10.0; // 简单的示例
};Map<Integer, Double> priceMap = Maps.asMap(productIds, priceFunction);System.out.println("Price of Product 1: " + priceMap.get(1));  // 输出 10.0
System.out.println("Price of Product 2: " + priceMap.get(2));  // 输出 20.0

方法介绍:

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

    public static <K, V> Map<K, V> asMap(Set<K> set, Function<? super K, V> function) {return new AsMapView(set, function);
    }
    
  2. 传入一个SortedSet和一个规则,返回一个SortMap

    public static <K, V> SortedMap<K, V> asMap(SortedSet<K> set, Function<? super K, V> function) {return new SortedAsMapView(set, function);
    }
    
  3. 传入一个NavigableSet和一个规则,返回一个NavigableMap

    public static <K, V> NavigableMap<K, V> asMap(NavigableSet<K> set, Function<? super K, V> function) {return new Maps.NavigableAsMapView(set, function);
    }
    

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

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

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

    public static <K, V> ImmutableMap<K, V> toMap(Iterable<K> keys, Function<? super K, V> valueFunction) {return toMap((Iterator)keys.iterator(), valueFunction);
    }
  2. 传入一个key值迭代器和一个规则返回一个不可变的map容器

    public static <K, V> ImmutableMap<K, V> toMap(Iterator<K> keys, Function<? super K, V> valueFunction) {Preconditions.checkNotNull(valueFunction);LinkedHashMap builder = newLinkedHashMap();//使用迭代器中的值作为key值,使用规则计算出的值作为value值,存入builder中while(keys.hasNext()) {Object key = keys.next();builder.put(key, valueFunction.apply(key));}//返回一个不可变的容器return ImmutableMap.copyOf(builder);
    }
    
  3. 根据value值容器和一个规则,直接交给重载函数去处理,返回一个不可变的Map容器

    public static <K, V> ImmutableMap<K, V> uniqueIndex(Iterable<V> values, Function<? super V, K> keyFunction) {return uniqueIndex((Iterator)values.iterator(), keyFunction);
    }
    
  4. 传入一个value值迭代器和一个规则返回一个不可变的map容器

    public static <K, V> ImmutableMap<K, V> uniqueIndex(Iterator<V> values, Function<? super V, K> keyFunction) {Preconditions.checkNotNull(keyFunction);Builder builder = ImmutableMap.builder();//使用迭代器中的值作为value值,使用规则计算出的值作为key值,存入builder中while(values.hasNext()) {Object value = values.next();builder.put(keyFunction.apply(value), value);}//返回一个不可变的容器return builder.build();
    }
    

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

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

public static ImmutableMap<String, String> fromProperties(Properties properties) {Builder builder = ImmutableMap.builder();Enumeration e = properties.propertyNames();//从properties获取的key和value,赋值到builder中while(e.hasMoreElements()) {String key = (String)e.nextElement();builder.put(key, properties.getProperty(key));}//返回一个不可变的Mapreturn builder.build();
}

返回Entry或Entry集合

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

public static <K, V> Entry<K, V> immutableEntry(@Nullable K key, @Nullable V value) {return new ImmutableEntry(key, value);
}

返回特殊的BiMap类

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

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

    public static <K, V> BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap) {return Synchronized.biMap(bimap, (Object)null);
    }
    
  2. 传入一个BiMap返回一个unmodifiableBiMap

    public static <K, V> BiMap<K, V> unmodifiableBiMap(BiMap<? extends K, ? extends V> bimap) {return new Maps.UnmodifiableBiMap(bimap, (BiMap)null);
    }
    

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

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

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

    public static <K, V1, V2> Map<K, V2> transformValues(Map<K, V1> fromMap, Function<? super V1, V2> function) {return transformEntries((Map)fromMap, asEntryTransformer(function));
    }
    
  2. 传入一个SortedMap和一个规则,返回一个由规则计算出来的新的Map

    public static <K, V1, V2> SortedMap<K, V2> transformValues(SortedMap<K, V1> fromMap, Function<? super V1, V2> function) {return transformEntries((SortedMap)fromMap, asEntryTransformer(function));
    }
    
  3. 传入一个NavigableMap和一个规则,返回一个由规则计算出来的NavigableMap

    public static <K, V1, V2> NavigableMap<K, V2> transformValues(NavigableMap<K, V1> fromMap, Function<? super V1, V2> function) {return transformEntries((NavigableMap)fromMap, asEntryTransformer(function));
    }
    
  4. 传入一个Map和一个Maps规定的规则格式,根据规则返回一个新的Map

    public static <K, V1, V2> Map<K, V2> transformEntries(Map<K, V1> fromMap, Maps.EntryTransformer<? super K, ? super V1, V2> transformer) {return (Map)(fromMap instanceof SortedMap?transformEntries((SortedMap)((SortedMap)fromMap), transformer):new Maps.TransformedEntriesMap(fromMap, transformer));
    }
    
  5. 传入一个NavigableMap和一个Maps规定的规则格式,根据规则返回一个新的NavigableMap

    public static <K, V1, V2> NavigableMap<K, V2> transformEntries(NavigableMap<K, V1> fromMap, Maps.EntryTransformer<? super K, ? super V1, V2> transformer) {return new Maps.TransformedEntriesNavigableMap(fromMap, transformer);
    }
    

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

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

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

// 对KeySet进行了过滤处理,使用了Set中的filter方法
private static class FilteredKeyMap<K, V> extends Maps.AbstractFilteredMap<K, V> {Predicate<? super K> keyPredicate;FilteredKeyMap(Map<K, V> unfiltered, Predicate<? super K> keyPredicate, Predicate<? super Entry<K, V>> entryPredicate) {super(unfiltered, entryPredicate);this.keyPredicate = keyPredicate;}protected Set<Entry<K, V>> createEntrySet() {return Sets.filter(this.unfiltered.entrySet(), this.predicate);}Set<K> createKeySet() {return Sets.filter(this.unfiltered.keySet(), this.keyPredicate);}public boolean containsKey(Object key) {return this.unfiltered.containsKey(key) && this.keyPredicate.apply(key);}
}
  1. 传入一个Map和过滤他的规则,返回一个新的Map

    public static <K, V> Map<K, V> filterKeys(Map<K, V> unfiltered, Predicate<? super K> keyPredicate) {Preconditions.checkNotNull(keyPredicate);Predicate<Map.Entry<K, ?>> entryPredicate = keyPredicateOnEntries(keyPredicate);return (Map)(unfiltered instanceof AbstractFilteredMap ? filterFiltered((AbstractFilteredMap)unfiltered, entryPredicate) : new FilteredKeyMap((Map)Preconditions.checkNotNull(unfiltered), keyPredicate, entryPredicate));}
    
  2. 传入一个SortedMap,然后交给filterEntries方法进行处理

    public static <K, V> SortedMap<K, V> filterKeys(SortedMap<K, V> unfiltered, Predicate<? super K> keyPredicate) {return filterEntries(unfiltered, keyPredicateOnEntries(keyPredicate));
    }
    
  3. 传入一个NavigableMap,然后交给filterEntries方法进行处理

    public static <K, V> NavigableMap<K, V> filterKeys(NavigableMap<K, V> unfiltered, Predicate<? super K> keyPredicate) {return filterEntries((NavigableMap)unfiltered, keyPredicateOnEntries(keyPredicate));
    }
    
  4. 传入一个BiMap,然后交给filterEntries方法进行处理

    public static <K, V> BiMap<K, V> filterKeys(BiMap<K, V> unfiltered, Predicate<? super K> keyPredicate) {Preconditions.checkNotNull(keyPredicate);return filterEntries((BiMap)unfiltered, keyPredicateOnEntries(keyPredicate));
    }
    

Sets

功能函数

功能 方法
创建不可变的set 1、ImmutableSet<E> immutableEnumSet(E anElement, E... otherElements)
2、ImmutableSet<E> immutableEnumSet(Iterable<E> elements)
创建HashSet 1、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)
创建线程安全的Set 1、Set<E> newConcurrentHashSet()
2、Set<E> newConcurrentHashSet(Iterable<? extends E> elements)
创建LinkedHashMap 1、LinkedHashSet<E> newLinkedHashSet()
2、LinkedHashSet<E> newLinkedHashSetWithExpectedSize(int expectedSize)
3、LinkedHashSet<E> newLinkedHashSet(Iterable<? extends E> elements)
创建TreeSet 1、TreeSet<E> newTreeSet()
2、TreeSet<E> newTreeSet(Iterable<? extends E> elements)
3、TreeSet<E> newTreeSet(Comparator<? super E> comparator)
创建IdentityHashSet Set<E> newIdentityHashSet()
创建CopyOnWriteArraySet 1、CopyOnWriteArraySet<E> newCopyOnWriteArraySet()
2、CopyOnWriteArraySet<E> newCopyOnWriteArraySet(Iterable<? extends E> elements)
创建EnumSet 1、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创建一个Set Set<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)
过滤Set 1、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

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

    public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(E anElement, E... otherElements) {//使用ImmutableEnumSet.asImmutable函数将EnumSet转为ImmutableSetreturn ImmutableEnumSet.asImmutable(EnumSet.of(anElement, otherElements));
    }//EnumSet.of方法是将anElement和otherElements合并成一个EnumSet
    public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {EnumSet<E> result = noneOf(first.getDeclaringClass());//将第一个参数先插入到EnumSet中result.add(first);//在将传入的数组全部插入到EnumSet中for (E e : rest)result.add(e);return result;
    }
    
  2. 根据一个集合创建一个不可变的Set

    public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(Iterable<E> elements) {//如果是一个ImmutableEnumSet,则直接转换为ImmutableEnumSetif(elements instanceof ImmutableEnumSet) {return (ImmutableEnumSet)elements;} else if(elements instanceof Collection) {//如果是一个Collection且不为空则,直接使用ImmutableEnumSet.asImmutable方法转化为ImmutableEnumSetCollection itr1 = (Collection)elements;return itr1.isEmpty()?ImmutableSet.of():ImmutableEnumSet.asImmutable(EnumSet.copyOf(itr1));} else {//其他类型,则获取他的迭代器,然后制作一个ImmutableEnumSetIterator itr = elements.iterator();if(itr.hasNext()) {EnumSet enumSet = EnumSet.of((Enum)itr.next());Iterators.addAll(enumSet, itr);return ImmutableEnumSet.asImmutable(enumSet);} else {return ImmutableSet.of();}}
    }
    

创建HashSet

  1. 直接new一个HashSet

    public static <E> HashSet<E> newHashSet() {return new HashSet();
    }
    
  2. 传入一个数组,返回一个HashSet

    public static <E> HashSet<E> newHashSet(E... elements) {//创建一个期望大小为elements.length的HashSetHashSet set = newHashSetWithExpectedSize(elements.length);//将数组中的元素,全部赋值给新的HashSetCollections.addAll(set, elements);return set;
    }
    
  3. 创建一个期望大小的HashSet

    public static <E> HashSet<E> newHashSetWithExpectedSize(int expectedSize) {//创建一个HashSet,大小为Maps.capacity方法计算后的值,这个方法最终返回原值的4/3return new HashSet(Maps.capacity(expectedSize));
    }
    
  4. 根据传入的集合创建一个HashSet

    public static <E> HashSet<E> newHashSet(Iterable<? extends E> elements) {return elements instanceof Collection?new HashSet(Collections2.cast(elements)):newHashSet((Iterator)elements.iterator());
    }
    
  5. 根据传入的迭代器创建一个HashSet

    public static <E> HashSet<E> newHashSet(Iterator<? extends E> elements) {//创建一个HashSetHashSet set = newHashSet();//使用Guava中的Iterators.addAll方法将迭代器中的元素添加到set中Iterators.addAll(set, elements);return set;
    }
    

创建线程安全的Set

  1. 使用ConcurrentHashMap创建一个Set

    public static <E> Set<E> newConcurrentHashSet() {//创建一个ConcurrentHashMap,使用newSetFromMap方法将ConcurrentHashMap的值转为Setreturn newSetFromMap(new ConcurrentHashMap());
    }
    
  2. 使用传入的集合创建一个线程安全的Set

    public static <E> Set<E> newConcurrentHashSet(Iterable<? extends E> elements) {//创建一个ConcurrentHashSetSet set = newConcurrentHashSet();//使用Guava中的Iterables.addAll方法将集合elements中的元素添加到set中Iterables.addAll(set, elements);return set;
    }
    

创建LinkedHashSet

  1. 直接创建一个LinkedHashSet

    public static <E> LinkedHashSet<E> newLinkedHashSet() {return new LinkedHashSet();
    }
    
  2. 创建一个期望大小的LinkedHashSet

    public static <E> LinkedHashSet<E> newLinkedHashSetWithExpectedSize(int expectedSize) {//返回一个LinkedHashSet,大小为expectedSize的4/3return new LinkedHashSet(Maps.capacity(expectedSize));
    }
    
  3. 根据传入的集合,返回一个LinkedHashSet

    public static <E> LinkedHashSet<E> newLinkedHashSet(Iterable<? extends E> elements) {//如果是一个Collection类型,则直接创建LinkedHashSet,并将集合中的值赋值给新的LinkedHashSetif(elements instanceof Collection) {return new LinkedHashSet(Collections2.cast(elements));} else {LinkedHashSet set = newLinkedHashSet();Iterables.addAll(set, elements);return set;}
    }

创建TreeSet

  1. 直接创建一个TreeSet

    public static <E extends Comparable> TreeSet<E> newTreeSet() {return new TreeSet();
    }
    
  2. 传入一个集合,返回一个TreeSet,并将集合中的元素赋值给TreeSet

    public static <E extends Comparable> TreeSet<E> newTreeSet(Iterable<? extends E> elements) {//创建一个TreeSetTreeSet set = newTreeSet();//将集合中的元素赋值给TreeSetIterables.addAll(set, elements);return set;
    }
    
  3. 传入一个Comparator,根据Comparator的规则创建一个TreeSet

    public static <E> TreeSet<E> newTreeSet(Comparator<? super E> comparator) {return new TreeSet((Comparator)Preconditions.checkNotNull(comparator));
    }
    

创建IdentityHashSet

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

public static <E> Set<E> newIdentityHashSet() {//使用Maps.newIdentityHashMap()方法创建一个IdentityHashMap,然后使用newSetFromMap方法将Map转为Setreturn newSetFromMap(Maps.newIdentityHashMap());
}

创建CopyOnWriteArraySet

  1. 直接创建一个CopyOnWriteArraySet

    public static <E> CopyOnWriteArraySet<E> newCopyOnWriteArraySet() {return new CopyOnWriteArraySet();
    }
    
  2. 根据传入的集合创建一个CopyOnWriteArraySet,并将集合中的数据赋值给CopyOnWriteArraySet

    public static <E> CopyOnWriteArraySet<E> newCopyOnWriteArraySet(Iterable<? extends E> elements) {//如果是一个Collection,直接将其转为Collection,如果不是则使用Lists创建一个ListObject elementsCollection = elements instanceof Collection?Collections2.cast(elements):Lists.newArrayList(elements);return new CopyOnWriteArraySet((Collection)elementsCollection);
    }
    

创建EnumSet

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

    public static <E extends Enum<E>> EnumSet<E> newEnumSet(Iterable<E> iterable, Class<E> elementType) {//根据传入的类型,创建一个setEnumSet set = EnumSet.noneOf(elementType);//将集合中的元素添加到set中Iterables.addAll(set, iterable);return set;
    }
    
  2. 传入一个集合,返回一个EnumSet

    public static <E extends Enum<E>> EnumSet<E> complementOf(Collection<E> collection) {if(collection instanceof EnumSet) {return EnumSet.complementOf((EnumSet)collection);} else {Preconditions.checkArgument(!collection.isEmpty(), "collection is empty; use the other version of this method");Class type = ((Enum)collection.iterator().next()).getDeclaringClass();return makeComplementByHand(collection, type);}
    }
    

根据一个Map创建一个Set

根据Map创建一个Set

public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {return Platform.newSetFromMap(map);
}
//Platform.newSetFromMap方法,一层一层往上追,最终可以看到,实际上使用的是Collections.SetFromMap类:private static class SetFromMap<E> extends AbstractSet<E> implements Set<E>, Serializable{private final Map<E, Boolean> m;  // The backing mapprivate transient Set<E> s;       // Its keySetSetFromMap(Map<E, Boolean> map) {//其实就是将map中的key集合作为一个Set了if (!map.isEmpty())throw new IllegalArgumentException("Map is non-empty");m = map;s = map.keySet();}
}

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

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

public static <E> Sets.SetView<E> difference(final Set<E> set1, final Set<?> set2) {Preconditions.checkNotNull(set1, "set1");Preconditions.checkNotNull(set2, "set2");//创建一个过滤规则(规则为,不能包含set2中的元素)final Predicate notInSet2 = Predicates.not(Predicates.in(set2));return new Sets.SetView(null) {//重写iterator,使用Iterators.filter过滤出不含set2元素的一个迭代器public Iterator<E> iterator() {return Iterators.filter(set1.iterator(), notInSet2);}//根据最终返回的迭代器计算长度public int size() {return Iterators.size(this.iterator());}//如果set1和set2中全部相等,就为空public boolean isEmpty() {return set2.containsAll(set1);}public boolean contains(Object element) {return set1.contains(element) && !set2.contains(element);}};
}

以两个Set的并集作为视图

public static <E> Sets.SetView<E> union(final Set<? extends E> set1, final Set<? extends E> set2) {Preconditions.checkNotNull(set1, "set1");Preconditions.checkNotNull(set2, "set2");//获取set2,中不包含set1的所有元素final Sets.SetView set2minus1 = difference(set2, set1);return new Sets.SetView(null) {//获取set1的全部长度和set2minus1视图的长度public int size() {return set1.size() + set2minus1.size();}public boolean isEmpty() {return set1.isEmpty() && set2.isEmpty();}public Iterator<E> iterator() {return Iterators.unmodifiableIterator(Iterators.concat(set1.iterator(), set2minus1.iterator()));}public boolean contains(Object object) {return set1.contains(object) || set2.contains(object);}//返回所有元素public <S extends Set<E>> S copyInto(S set) {set.addAll(set1);set.addAll(set2);return set;}public ImmutableSet<E> immutableCopy() {return (new Builder()).addAll(set1).addAll(set2).build();}};
}

以两个Set的交集作为视图

public static <E> Sets.SetView<E> intersection(final Set<E> set1, final Set<?> set2) {Preconditions.checkNotNull(set1, "set1");Preconditions.checkNotNull(set2, "set2");//创建一个过滤规则(规则为:全部set2元素)final Predicate inSet2 = Predicates.in(set2);return new Sets.SetView(null) {//返回set1中包含set2中的所有元素public Iterator<E> iterator() {return Iterators.filter(set1.iterator(), inSet2);}//根据计算出的迭代器计算长度public int size() {return Iterators.size(this.iterator());}//根据迭代器判断是否为空public boolean isEmpty() {return !this.iterator().hasNext();}public boolean contains(Object object) {return set1.contains(object) && set2.contains(object);}public boolean containsAll(Collection<?> collection) {return set1.containsAll(collection) && set2.containsAll(collection);}};
}

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

public static <E> Sets.SetView<E> symmetricDifference(Set<? extends E> set1, Set<? extends E> set2) {Preconditions.checkNotNull(set1, "set1");Preconditions.checkNotNull(set2, "set2");return difference(union(set1, set2), intersection(set1, set2));
}

过滤Set

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

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

public static <E> Set<E> filter(Set<E> unfiltered, Predicate<? super E> predicate) {//如果传入的Set为SortedSet类型,使用传入SortedSet的方法进行处理if(unfiltered instanceof SortedSet) {return filter((SortedSet)((SortedSet)unfiltered), predicate);} else if(unfiltered instanceof Sets.FilteredSet) {Sets.FilteredSet filtered = (Sets.FilteredSet)unfiltered;Predicate combinedPredicate = Predicates.and(filtered.predicate, predicate);return new Sets.FilteredSet((Set)filtered.unfiltered, combinedPredicate);} else {return new Sets.FilteredSet((Set)Preconditions.checkNotNull(unfiltered), (Predicate)Preconditions.checkNotNull(predicate));}
}

往期推荐

  • 《SpringBoot》EasyExcel实现百万数据的导入导出
  • 《SpringBoot》史上最全SpringBoot相关注解介绍
  • Spring框架IoC核心详解
  • 万字长文带你窥探Spring中所有的扩展点
  • 如何实现一个通用的接口限流、防重、防抖机制
  • 万字长文带你深入Redis底层数据结构
  • volatile关键字最全原理剖析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/908460.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Autodesk Maya 2026 Multilanguage (macOS, Windows) - 三维动画和视觉特效软件

Autodesk Maya 2026 Multilanguage (macOS, Windows) - 三维动画和视觉特效软件Autodesk Maya 2026 Multilanguage (macOS, Windows) - 三维动画和视觉特效软件 三维计算机动画、建模、仿真和渲染软件 请访问原文链接:https://sysin.org/blog/autodesk-maya/ 查看最新版。原创…

Autodesk AutoCAD 2026 (macOS, Windows) - 自动计算机辅助设计软件

Autodesk AutoCAD 2026 (macOS, Windows) - 自动计算机辅助设计软件Autodesk AutoCAD 2026 (macOS, Windows) - 自动计算机辅助设计软件 计算机辅助设计 (CAD) 软件 请访问原文链接:https://sysin.org/blog/autodesk-autocad/ 查看最新版。原创作品,转载请保留出处。 作者主页…

VMware Aria Operations for Logs 8.18.3 新增功能简介

VMware Aria Operations for Logs 8.18.3 新增功能简介VMware Aria Operations for Logs 8.18.3 - 集中式日志管理 请访问原文链接:https://sysin.org/blog/vmware-aria-operations-for-logs/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org集中式日志管理 VMwa…

在 VS Code 中,一键安装 MCP Server!

大家好!我是韩老师。 本文是 MCP 系列文章的第三篇。之前的两篇文章是: Code Runner MCP Server,来了! 从零开始开发一个 MCP Server!经过之前两篇文章的介绍,相信不少童鞋已经用上甚至开发起了第一个 MCP Server。 不过呢,还是遇到一些童鞋在安装/配置 MCP Server 的时…

读DAMA数据管理知识体系指南36元数据管理概念(上)

读DAMA数据管理知识体系指南36元数据管理概念(上)1. 业务驱动因素 1.1. 可靠且良好管理元数据有助于1.1.1. 通过提供上下文语境和执行数据质量检查提高数据的可信度1.1.2. 通过扩展用途增加战略信息(如主数据)的价值1.1.3. 通过识别冗余数据和流程提高运营效率1.1.4. 防止使…

AMD CDNA介绍(上)

AMD CDNA介绍 AMD CDNA处理器采用并行微架构,旨在为通用数据并行应用提供一个出色的平台。需要高带宽或计算密集型的数据密集型应用程序,这是在AMD CDNA处理器上运行的候选者。 AMD CDNA生成系列处理器的框图,如图5-10所示。图5-10 AMD CDNA生成系列处理器的框图 CDNA设备包…

AMD Instinct™MI300系列微架构杂谈

AMD Instinct™MI300系列微架构 AMD Instinct MI300系列加速器基于AMD CDNA 3架构,旨在为HPC、人工智能(AI)和机器学习(ML)工作负载提供领先性能。AMD Instinct MI300系列加速器非常适合极端的可扩展性和计算性能,可以在单个服务器到世界上最大的EB级超级计算机的所有设备…

在Eager模式下对Llama 2 7B模型进行性能评估技术

在Eager模式下对Llama 2 7B模型进行性能评估 指定--compile none以使用Eager模式。 1)--compile:设置为none以使用Eager模式 2)--profile:启用torch.profiler的跟踪功能 3)--checkpoint_path:检查点路径 4)--prompt:输入提示 5)--max_new_tokens:最大新的token数 6)…

使用 torch.compile 加速视觉Transformer

使用 torch.compile 加速视觉Transformer视觉Transformer(ViT)是一个类似 BERT的transformer编码器模型,在大规模的图像集合上,使用有监督方式进行了预训练,就是在分辨率为 224224 像素的 ImageNet-21k 数据集上预训练的。以下是如何使用这个模型将 COCO 2017 数据集中的一…

推荐技术书《AI芯片开发核心技术详解》(1)、《智能汽车传感器:原理设计应用》(2)、《TVM编译器原理与实践》(3)、《LLVM编译器原理与实践》(4),谢谢

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

GPU到GPU通信选项技术

GPU到GPU通信选项技术将讨论使用AMD Instinct™MI250和AMD InstinctTM MI250X GPU的系统中的GPU到GPU通信选项。每个MI250(X)GPU由两个图形计算芯片(GCD)组成。如图4-20所示,显示了具有4个MI250 GPU(8个GCD)的节点的示意图。每个绿色框代表一个MI250 GPU和两个GCD。GCD通…

visual stdio 使用CMake

基础知识 工具>选项>CMake>常规 选中从不使用CMake预设重启 visual stdio,点击打开本地文件夹(F),打开CMakeList.txt根目录此时会在CMake根目录自动生成CMakeSettings.json文件,使用visual stdio文件打开CMakeSettings.json如果打开时,是json文件时,可以右键CMa…