文章7 | 阅读 2766 | 点赞0
Guava中新增加了一些集合类型,是对JDK集合类型的补充,使开发者更方便使用集合类型来实现业务功能
首先我们来看一下日常研发中常用到的一个场景,统计一个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<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默认是排好序的,是按元素来进行排序的而不是元素的个数
在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的各种实现
实现 | 键行为类似 | 值行为类似 |
---|---|---|
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap | LinkedHashMap | LinkedList |
LinkedHashMultimap | LinkedHashMap | LinkedHashMap |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap | ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
在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 |
在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是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象
ClassToInstanceMap<Number> numberDefaults= MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class,6);
还有RangeSet、RangeMap平时用的比较少,大家有需要可以去Guava官网上了解一下
https://github.com/google/guava/wiki/NewCollectionTypesExplained
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/pzjtian/article/details/106677410
内容来源于网络,如有侵权,请联系作者删除!