guava collections 专题

    在日常编码中,大量的使用诸如Map<K, List>或者Map<K, Set>这种形式的集合时,你是否考虑在java collection的基础之上在封装些更加合适的集合类型呢?日常编码中有没有遇到过一些不可变的集合呢?同样,你一样可能需要一种双向map来实现key-value的互相映射。上面的这些小小的功能需求,其实都可以通过guava collection来实现。这里我只是简单的介绍一下在guava中我们可以怎么样优美的实现前面的需求:

Immutable Collections

    在immutable collections方面,java Collections 框架提供了一系列unmodifiableXXX的静态方法供使用,这些unmodifiableXXX实际上是原有集合的视图包装,所以可以认为新生成的不变集合和原有集合是同一对象,只是不变集合不能调用修改操作。这种效果有时并不是真正想要的,有时需要的是生成的不变集合和原有集合是分离的,原有集合的后续操作不影响不变集合。guava就提供了该功能,具体的就包括ImmutableList、ImmutableMap、ImmutableSet等。下面给出一个示例片断:

原有使用java.util.Collections的方法示例:

 List list = new ArrayList(); 
 list.add("1"); 
 list.add("2");
 list.add("3"); 
 List immutableList = Collections.unmodifiableList(list);

使用guava ImmutableList示例:

List immutableList = ImmutableList.of("1","2","3");

    guava ImmutableXXX都是通过调用静态的of方法生成新的不变集合,该方法的参数是个可变数组。因为ImmutableFoo只提供读操作并自己维护数据,所以性能方面会比java.util中集合类有所提高。另外要说的是,不变集合并不能左右其包含的元素是否可变,所以不变集合中的元素最好也是不变的。

Multiset & Multimap

    java.util.Set是个无序且元素不重复的集合。而Multiset是个无序但添加元素可重复的集合,对添加的重复元素,以计数表示多少。Multiset的实现也是支持多种类型的(比如Hash、LinkedList等)下面是使用片断:

Multiset set = HashMultiset.create(); 
set.add("kafka0102"); 
set.add("kafka0102");
System.out.println(set.count("kafka0102"));//输出2 
set.setCount("kafka0102", 5);
System.out.println(set.count("kafka0102"));//输出5

    这个Multiset还是有很多应用场景的,比如统计用户访问计数,没有Multiset,就需要使用如Map来做,每次累加都需要先取出原有的计数值再加一后放回去,自然不如Multiset使用的方便。

    Multimap也是很方便实用的集合,对于形如Multimap的map,它相当于Map>。如果实用Map来实现Multimap的功能,可想又是对Map的value进行三部曲操作。Multimap的实现也是支持多种类型的(比如Hash、LinkedList等)。使用Multimap的示例代码如下:

Multimap map = HashMultimap.create();
map.put("kafka0102","1");
map.put("kafka0102","2");
System.out.println(map.get("kafka0102"));//输出[2, 1]

BiMap

    BiMap(bidirectional map)是个双向的map。java.util.Map是个正向Map,也就是根据key查value,如果需要根据value查key,或者需要反向得到Map,BiMap就是很好的选择,否则就需要两个Map来做。它的具体实现类有:EnumBiMap, EnumHashBiMap, HashBiMap, ImmutableBiMap。示例代码如下:

BiMap map = HashBiMap.create();
map.put("kafka0102","1");
System.out.println(map.get("kafka0102"));
System.out.println(map.inverse().get("1"));