14/100

Guava中新增加了一些集合类型,是对JDK集合类型的补充,使开发者更方便使用集合类型来实现业务功能

Multiset

首先我们来看一下日常研发中常用到的一个场景,统计一个list中每个元素出现的次数,我们大概会这样写:

List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("b"); list.add("b"); Map<String,Integer> countMap = new HashMap<String,Integer>(); for(String str : list){ if(countMap.get(str) != null){ countMap.put(str,countMap.get(str) 1); } else { countMap.put(str,1); } }

显然这样的写法,看起来还是挺笨拙的

Guava提供了Multiset,虽然名字带有Set,但它可以添加重复的元素

Multiset可以看成是ArrayList和Map的结合体

下面我们来看一下Multiset的实际用法

//通过create()方法创建 Multiset<String> multiset = HashMultiset.create(); //可直接添加元素 multiset.add("a"); multiset.add("b"); multiset.add("c"); multiset.add("c"); multiset.add("c"); List<String> list = new ArrayList<String>(); list.add("xx"); list.add("yy"); list.add("zz"); //也可用addAll方法添加集合进来 multiset.addAll(list); //获取元素"c"的计数 System.out.println(multiset.count("c")); //返回去重后的元素set集合 Set<String> set = multiset.elementSet(); //multiset所有元素的个数 System.out.println("multiset.size():" multiset.size()); //multiset去重后的元素个数 System.out.println("elementSet().size():" multiset.elementSet().size()); //元素迭代 Iterator<String> it = multiset.iterator(); while(it.hasNext()){ System.out.println(it.next()); } //可以通过设置元素的计数,来批量的添加元素,当然能加也能减 multiset.setCount("c",5); //将元素的计数设为0,就相当于移除所有的"c"元素 multiset.setCount("c",0); //移除一个元素 multiset.remove("c"); //移除两个"c"元素 multiset.remove("c",2);

可以看出来,Multiset包含了基本的集合操作外,还有一些特有的操作,比如setCount()、按个数remove()

Guava提供了多种Multiset的实现,大致对应JDK中Map的各种实现:

Map 对应的Multiset 是否支持null元素 HashMap HashMultiset 是 TreeMap TreeMultiset 是 LinkedHashMap LinkedHashMultiset 是 ConcurrentHashMap ConcurrentHashMultiset 否 ImmutableMap ImmutableMultiset 否

SortedMultiset

SortedMultiset支持高效的获取指定范围的子集

SortedMultiset<String> sortedMultiset = TreeMultiset.create(); sortedMultiset.setCount("c",5); sortedMultiset.setCount("a",3); sortedMultiset.setCount("b",2); //获取第一个元素 sortedMultiset.firstEntry().getElement(); //获了最后一个元素 sortedMultiset.lastEntry().getElement(); //获取子集 SortedMultiset<String> subMultiset = sortedMultiset.subMultiset("a", BoundType.OPEN,"b",BoundType.CLOSED);

需要注意,SortedMultiset默认是排好序的,是按元素来进行排序的而不是元素的个数

Multimap

在JDK中Map是存储Key-value型数据结构的,并且Key相同时会被覆盖掉,比如

Map<String,String> map = new HashMap<String,String>(); map.put("key","value1"); map.put("key","value2");

最终map里只会存key->value2的值

在很多时候,我们需要一个key对应多个值,在JDK中只能以类似于Map<K,List>这种形式来表达,操作起来很不方便

Guava为我们提供了Multimap,可以用来做一个Key映射多个值的操作

Multimap multimap = ArrayListMultimap.create(); //新增元素,直接put multimap.put("a","123"); multimap.put("a","111"); multimap.put("b","456"); multimap.put("d","789"); Multimap multimap1 = LinkedListMultimap.create(); multimap1.put("a","a1_value"); multimap1.put("k2","k2_value"); //使用putAll方法可以添加一个multimap,这个跟JDK中的putAll一样,而且key相同时会进行合并 multimap.putAll(multimap1); List<String> list = Lists.newArrayList("a_value1","a_value2","a_value3"); //还可以指定key进行批量添加元素,注意此处是追加到key中,不是替换 multimap.putAll("a",list); //multimap中的所有键值对,重复的算多个 System.out.println(multimap.size()); //key的个数 System.out.println(multimap.keySet().size()); //移除指定key的指定value multimap.remove("a","111"); System.out.println(multimap); //移除整个key的所有value multimap.removeAll("a"); System.out.println(multimap); //替换指定key的value multimap.replaceValues("b",Lists.newArrayList("b1_value","b2_value")); //是否包含指定的key System.out.println(multimap.containsKey("d")); //是否包含指定的键值对 System.out.println(multimap.containsEntry("d","789")); //获取multimap中所有的value System.out.println(multimap.values()); //返回Multiset System.out.println(multimap.keys()); //返回Map类型 Map<String,List<String>> map = multimap.asMap(); //清空整个集合 multimap.clear(); System.out.println(multimap);

Multimap的各种实现

guava是限流场景吗(Guava系列之新的集合类型)(1)

BiMap

在JDK中,如果我们要维护一个双向Map,需要定义两个Map来存储,并且两个要同时进行变更

Map<String,String> map1 = Maps.newHashMap(); Map<String,String> map2 = Maps.newHashMap(); map1.put("Hello","Kai"); map2.put("Kai","Hello");

Guava提供了BiMap,它是一种特殊的Map,可以实现键值的反转

public static void main(String[] args){ BiMap biMap = HashBiMap.create(); biMap.put("a","123"); System.out.println(biMap); //对键值对进行反转 System.out.println(biMap.inverse()); //试图将一个key映射到已经存在的值上,会抛异常 biMap.put("b","123"); //强值将一个key映射到已经存在的值上,会将原来的key覆盖掉 biMap.forcePut("b","123"); System.out.println(biMap); }

可以看出,因为BiMap要支持反转,所以它的key和value都必须是唯一的,要不然反转过来就存在一对多的情况

BiMap的各种实现

键–值实现 值–键实现 对应的BiMap实现 HashMap HashMap HashBiMap ImmutableMap ImmutableMap ImmutableBiMap EnumMap EnumMap EnumBiMap EnumMap EnumMap EnumHashBiMap

Table

在JDK中当需要做key映射到Key-value对时,你需要这样写Map<K,Map<K,V>>,这种写法同样不够友好,同时也不便维护

这实际上就是一个表格的行、列、值的结构,Guava里面提供了表格来解决这种场景

//创建row,column,value结构的table Table<String,String,Integer> table = HashBasedTable.create(); table.put("a1","c1",23); table.put("a1","c2",77); table.put("a2","c2",44); //通过rowKey获取columnKey->value的映射关系 System.out.println(table.row("a1")); //通过columnKey获取rowKey ->value的映射关系 System.out.println(table.column("c2"));

Table有如下几种实现:

ClassToInstanceMap

ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象

ClassToInstanceMap<Number> numberDefaults= MutableClassToInstanceMap.create(); numberDefaults.putInstance(Integer.class,6);

还有RangeSet、RangeMap平时用的比较少,大家有需要可以去Guava官网上了解一下 https://github.com/google/guava/wiki/NewCollectionTypesExplained

,