Guava(4) Collection Utilities

3.Collection Utilities

据说是guava最受欢迎的部分,基于Collections延伸的集合静态处理方法。

Interface JDK or Guava? Corresponding Guava utility class
Collection JDK Collections2
List JDK Lists
Set JDK Sets
SortedSet JDK Sets
Map JDK Maps
SortedMap JDK Maps
Queue JDK Queues
Multiset Guava Multisets
Multimap Guava Multimaps
BiMap Guava Maps
Table Guava Tables

JDK中的常用集合以及对应的guava中的工具类如上所示。

3.1Constructors

非常方便的创建集合实例。

Set<Integer> copySet = Sets.newHashSet(1, 2, 3);
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);
Multiset<String> multiset = HashMultiset.create();

3.2Iterables

Iterable<String> strings = Iterables.concat(copySet, theseElements);
int occurrences = Iterables.frequency(strings, "a");
Iterable<List<String>> lists = Iterables.partition(strings, 3);
String first = Iterables.getFirst(strings, "");
String last = Iterables.getLast(strings);
String theElement = Iterables.getOnlyElement(strings);
Iterables.elementsEqual(copySet, copySet2);

3.3Lists

List<Integer> countUp = Ints.asList(1, 2, 3, 4, 5);
List<Integer> countDown = Lists.reverse(theList); // {5, 4, 3, 2, 1}
List<List<Integer>> parts = Lists.partition(countUp, 2); // { {1, 2}, {3, 4}, {5}}
Longs.max(1, 2, 3);
Ints.max(1, 2, 3);
Collections.max(Arrays.asList(1, 2, 3)); // 不推荐
max(asList(1, 2, 3)); // 推荐

像max,asList这些方法都是静态的,直接引用看起来可读性更好,更简洁。

3.4Sets

Sets中引入了很多对区间的操作,就像Range那样,返回值是一个SetView。

Sets.SetView<Integer> set1 = Sets.union(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4));
// [1, 2, 3, 4]
Sets.SetView<Integer> set2 = Sets.intersection(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4));// [3]
Sets.SetView<Integer> set3 = Sets.difference(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4));// [1, 2]
Sets.SetView<Integer> set4 = Sets.symmetricDifference(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4)); // [1, 2, 4]

SetView可以直接当做Set使用,其中有两个常用的方法,copyInto可以将视图拷贝到可变集合中,immutableCopy可以将视图拷贝到一个不可变集合。

public abstract static class SetView<E> extends AbstractSet<E> {
    ...
    @CanIgnoreReturnValue
    public <S extends Set<E>> S copyInto(S set) {
      set.addAll(this);
      return set;
    }

    public ImmutableSet<E> immutableCopy() {
      return ImmutableSet.copyOf(this);
    }    
    ...
}

Sets还提供了笛卡尔积和子集的实现。

Set<String> animals = ImmutableSet.of("gerbil", "hamster");
Set<String> fruits = ImmutableSet.of("apple", "orange", "banana");
Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
// [[gerbil, apple], [gerbil, orange], [gerbil, banana], [hamster, apple], [hamster, orange], [hamster, banana]]
Set<Set<String>> animalSets = Sets.powerSet(animals);
// [[][gerbil][hamster][gerbil, hamster]]

3.5Maps

Maps设计了很多很有特色的方法。

List<String> strings = Lists.newArrayList("alpha", "beta", "3");
ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings, (String string) -> {
    assert string != null;
    return string.length();
});

uniqueIndex可以通过自定义的某种规则,将指定集合转成Map,如果不是唯一的,可以使用Multimaps.index。

ImmutableListMultimap<Integer, String> stringsByIndex = Multimaps.index(strings, (String string) -> {
    assert string != null;
    return string.length();
}); // {5=[alpha, gamma], 4=[beta]}

difference可以比较Map之间的差异,生成四个视图。

Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5);
MapDifference<String, Integer> diff = Maps.difference(left, right);

diff.entriesInCommon(); // {"b" => 2}
diff.entriesDiffering(); // {"c" => (3, 4)} 
// Map<String, MapDifference.ValueDifference<Integer>>
diff.entriesOnlyOnLeft(); // {"a" => 1}
diff.entriesOnlyOnRight(); // {"d" => 5}

3.6Multisets

针对出现次数的一些常用方法。

Multiset<String> multiset1 = HashMultiset.create();
multiset1.add("a", 2);

Multiset<String> multiset2 = HashMultiset.create();
multiset2.add("a", 5);

multiset1.containsAll(multiset2); // returns true: all unique elements are contained,
// even though multiset1.count("a") == 2 < multiset2.count("a") == 5
Multisets.containsOccurrences(multiset1, multiset2); // returns false

Multisets.removeOccurrences(multiset2, multiset1); // multiset2 now contains 3 occurrences of "a"

multiset2.removeAll(multiset1); // removes all occurrences of "a" from multiset2, even though multiset1.count("a") == 2
multiset2.isEmpty(); // returns true

Multiset<String> multiset = HashMultiset.create();
multiset.add("c", 1);
multiset.add("b", 5);
multiset.add("a", 3);
ImmutableMultiset<String> highestCountFirst = Multisets.copyHighestCountFirst(multiset);
// [b x 5, a x 3, c]

3.7Multimaps

index,与Maps.uniqueIndex类似,区别是后者要求元素唯一,否则报错。

// Multimaps.index
ImmutableSet<String> digits = ImmutableSet.of(
        "zero", "one", "two", "three", "four",
        "five", "six", "seven", "eight", "nine");
Function<String, Integer> lengthFunction = new Function<String, Integer>() {
    public Integer apply(String string) {
        return string.length();
    }
};
ImmutableListMultimap<Integer, String> digitsByLength = Multimaps.index(digits, lengthFunction);
// {4=[zero, four, five, nine], 3=[one, two, six], 5=[three, seven, eight]}

// Maps.uniqueIndex
List<String> strings = Lists.newArrayList("beta", "gamma");
ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings, new Function<String, Integer> () {
    public Integer apply(String string) {
        return string.length();
    }
});
// {3=abc, 5=gamma}

invertFrom,置换key-value。

ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.putAll("b", Ints.asList(2, 4, 6));
multimap.putAll("a", Ints.asList(4, 2, 1));
multimap.putAll("c", Ints.asList(2, 5, 3));
TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap.create());

forMap,将普通Map转成Multimap。

Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2);
SetMultimap<String, Integer> multimap = Multimaps.forMap(map);
// multimap maps ["a" => {1}, "b" => {1}, "c" => {2}]
Multimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap.create());

warppers,提供了默认的初始化封装实现。

Multimap type Unmodifiable Synchronized Custom
Multimap unmodifiableMultimap synchronizedMultimap newMultimap
ListMultimap unmodifiableListMultimap synchronizedListMultimap newListMultimap
SetMultimap unmodifiableSetMultimap synchronizedSetMultimap newSetMultimap
SortedSetMultimap unmodifiableSortedSetMultimap synchronizedSortedSetMultimap newSortedSetMultimap

一个例子,支持传入Supplier。

ListMultimap<String, Integer> myMultimap = Multimaps.newListMultimap(
        Maps.<String, Collection<Integer>>newTreeMap(),
        new Supplier<LinkedList<Integer>>() {
            public LinkedList<Integer> get() {
                return Lists.newLinkedList();
            }
        });

需要注意的是:

第一个参数是源引用,必须是空Map;

第二个参数是Collection的构造器,但是Multimap.get(key)的返回类型并不是Supplier的类型,是一个封装的List。

3.8Tables

4.Extension Utilities

4.1Forwarding

4.2Decorators

4.3PeekingIterator

4.4AbstractIterator