GuavaHashMultimap使用及注意事项大家好morning|noon|afternoon|evening|morninggoodmorning|noon|afternoon|evening|morninggoodmorning|morning|noon|afternoon|evening|earlymorning我给大家介绍一个比较基础的HashMultmap知识点你今天;guava基本上可以说是一个Java开发项目,一个大概率会引入的包。今天介绍的主角是一个特殊的容器——HashMultmap。它的数据结构可以简单理解为Map>,那为什么突然想到引入呢?因为昨天理解不够,就当成一个Map>,结果出问题了;既然如此,我们就来看看,反思一下吧1.数据模型介绍通常来说,在使用一个新的数据对象时,首先要了解它的数据模型;直接看源码,我们会发现实际的数据存储结构是Map>abstractclassAbstractMapBasedMultimapextendsAbstractMultimapimplementsSerializable{privatetransientMap>map;}jdk中Map的实现有很多种,那么到底是哪一种呢?从构造方法开始,看一下这个map成员的初始化过程this.expectedValuesPerKey=2;Preconditions.checkArgument(expectedValuesPerKey>=0);this.expectedValuesPerKey=expectedValuesPerKey;}privateHashMultimap(Multimapmultimap){super(Platform.newHashMapWithExpectedSize(multimap.keySet().size()));this.expectedValuesPerKey=2;this.putAll(multimap);}重点在于Platform.newHashMapWithExpectedSize,熟悉的朋友已经可以给出答案了。这个映射就是我们常用的HashMap。接下来需要注意的是value中的Collection,它是一个什么样的容器;对于它,put(key,value)添加元素时的关键源码如下publicbooleanput(@NullableKkey,@NullableVvalue){地图。得到(钥匙);if(collection==null){collection=this.创建集合(键);if(collection.add(value)){++this.totalSize;this.map.put(key,collection);返回真;}else{thrownewAssertionError("NewCollectionviolatedtheCollectionspec");}}elseif(collection.add(value)){++this.totalSize;返回真;}else{返回错误;}}这种写法相信大家都不陌生。如果存在,则直接添加到容器中;如果不存在,则通过createCollection创建容器,塞入Map;具体实现逻辑如下//com.google.common.collect.HashMultimap#createCollectionSetcreateCollection(){returnPlatform.newHashSetWithExpectedSize(this.expectedValuesPerKey);}所以HashMultimap的底层数据存储就是我们的老朋友HashMap>2。简单介绍基本上,HashMultimap的使用姿势很简单。这是一个简单的例子来演示它。基本上,你可以看到它。2.1容器创建//创建一个默认的HashMap>,容器的初始容量同HashMap的默认值HashMultimapmap=HashMultimap.create();//当我们知道容器个数,推荐使用如下方法,//HashMap设置容量为8,每个HashSet容量初始化为16HashMultimapmap2=HashMultimap.create(8,16);//另一个case基于MultMap创建HashMultimapmap3=HashMultimap.create(map);注意上面的第三种实现,需要理解的是,map3.get(key)!=map.get(key)是在原有容器的基础上初始化的新容器,它的值是一个新的容器对象。之前值中的所有元素,都被塞进新的容器中,而不是直接引用的容器对象(这样是不是要深拷贝而不是浅拷贝?)2.2添加元素//添加单个elementmap.put("hello",510);//添加多个元素map.putAll("skill",Arrays.asList(1,2,3,4,1));注意,因为value是一个HashSet,重复的元素会被忽略,插入的元素会被忽略重新声明,添加重复的元素会被忽略(没有错了,我这里有问题。。。)2.3移除元素//移除技能对应集合中value=3的元素map.remove("skill",3);//移除keymap.removeAll("hello");2.4替换元素如果我们想用一个新的集合来替换整个值,我们可以使用replaceValue//直接替换技能对应的值集合,新的值是{100,200,300}map.replaceValues(“技能”,Arrays.asList(100,200,300));2.5获取元素并遍历//获取对应的值集合,如果不存在则返回空集合(不是null,简直是体贴)Setset=map.get("skill");foreachiterationfor(Map.Entryentry:map.entries()){System.out.println(entry.getKey()+":"+entry.getValue());}注意上面的迭代成员Map.Entry,它的key还是HashMap的key,value是这个集合中的每一个元素,比如容器中的value是("skill":[100,200,300])时,输出如下skill:200skill:100skill:300````####2.6Outputallkeys//输出所有keys,map.keys()//输出keysetmap.keySet();它们之间有什么区别?看一个例子HashMultimapmap=HashMultimap.create();map.replaceValues("skill",Arrays.asList(100,200,300));System.out.println("keys="+map.keys());System.out.println("keySet="+map.keySet());输出如下keys=[skillx3]keySet=[skill]上面的`skillx3`是什么,其实就是说`skill`有3个,返回的容器可以理解为一个List,不是为了去重和下面的`KeySet()`返回一个Set,会去重####2.7输出所有的valuemap.values()通过上面很容易理解这一点,所有的值合并成一个List,接下来,我们来看两个遍历方法HashMultimapmap=HashMultimap.create();map.putAll("skill",Arrays.asList(100,200,300));map.put("a",100);for(Integerv:map.values()){System.out.println(v);}实际输出如下:100100200300###三、总结这里主要介绍一下Gauva的容器HashMultimap的数据模型和使用姿势和知识点比较基础。实际使用的时候请记住,它可以看作是一个简单易用的`HashMap>`,注意value中的元素不能是重复。那么当我们希望值是一个List时,我们该如何调整呢?-可以用LinkedMultiValueMap代替,它的底层数据结构其实是`HashMap>`-也可以用`ArrayListMultimap`,底层数据结构是`HashMap>`最后,我想提一下,这些guava容器的源代码并不难读,设计思路也很典型。比如我们基于jdk基础容器实现一个类似的容器,如何优雅的实现毛呢布?这里给出一个标准答案,强烈建议有兴趣的朋友看看##一个灰色的联系方式,还不如没有书。以上内容纯属家庭意见。由于个人能力有限,难免有疏漏和错误。如果大家发现bug或者有更好的建议,欢迎大家批评指正,不胜感激——个人站点:[https://blog.hhui.top](https://blog.hhui.top)-微博地址:[小灰灰博客](https://weibo.com/p/1005052169825577/home)-QQ:一辉灰/3302797840-微信公众号:**灰色博客**