Java項(xiàng)目Guava包?HashMultimap使用及注意事項(xiàng)
今天給大家介紹一個(gè)相對(duì)基礎(chǔ)的知識(shí)點(diǎn) HashMultmap;
guava基本上可以說(shuō)是java開(kāi)發(fā)項(xiàng)目中,大概率會(huì)引入的包,今天介紹的主角是一個(gè)特殊的容器 -- HashMultmap,可以簡(jiǎn)單的將它的數(shù)據(jù)結(jié)構(gòu)理解為Map<K, Set<V>>
那么為什么會(huì)突然想到介紹一下它呢,因?yàn)樽蛱靹傄驗(yàn)閷?duì)它理解不夠深刻,把它當(dāng)作了Map<K, List<V>>來(lái)使用,結(jié)果出了問(wèn)題;既然如此那就好好盤(pán)一盤(pán),反思一下
1. 數(shù)據(jù)模型介紹
正常來(lái)講,在使用一個(gè)新的數(shù)據(jù)對(duì)象時(shí),我們應(yīng)該先的了解它的數(shù)據(jù)模型;
直接看源碼,會(huì)發(fā)現(xiàn)實(shí)際存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu)為 Map<K, Collection<V>>
abstract class AbstractMapBasedMultimap<K, V> extends AbstractMultimap<K, V> implements Serializable {
private transient Map<K, Collection<V>> map;
}再jdk中Map也有很多實(shí)現(xiàn),那么具體是哪個(gè)呢?
從構(gòu)造方法出發(fā),來(lái)看下這個(gè)map成員的初始化過(guò)程
private HashMultimap(int expectedKeys, int expectedValuesPerKey) {
super(Platform.newHashMapWithExpectedSize(expectedKeys));
this.expectedValuesPerKey = 2;
Preconditions.checkArgument(expectedValuesPerKey >= 0);
this.expectedValuesPerKey = expectedValuesPerKey;
}
private HashMultimap(Multimap<? extends K, ? extends V> multimap) {
super(Platform.newHashMapWithExpectedSize(multimap.keySet().size()));
this.expectedValuesPerKey = 2;
this.putAll(multimap);
}關(guān)鍵點(diǎn)就在 Platform.newHashMapWithExpectedSize,熟悉的小伙伴已經(jīng)能很快給出答案了,這個(gè)map就是我們常用的HashMap
接下來(lái)需要關(guān)注的就是value中的Collection,是什么容器類型了;對(duì)于它,則從添加元素的時(shí)候來(lái)定位put(key, value)
關(guān)鍵源碼如下
public boolean put(@Nullable K key, @Nullable V value) {
Collection<V> collection = (Collection)this.map.get(key);
if (collection == null) {
collection = this.createCollection(key);
if (collection.add(value)) {
++this.totalSize;
this.map.put(key, collection);
return true;
} else {
throw new AssertionError("New Collection violated the Collection spec");
}
} else if (collection.add(value)) {
++this.totalSize;
return true;
} else {
return false;
}
}這個(gè)寫(xiě)法相信大家都不會(huì)陌生,存在時(shí),直接添加到容器;不存在時(shí),則通過(guò) createCollection來(lái)創(chuàng)建容器,并塞入Map;其具體的實(shí)現(xiàn)邏輯如下
// com.google.common.collect.HashMultimap#createCollection
Set<V> createCollection() {
return Platform.newHashSetWithExpectedSize(this.expectedValuesPerKey);
}所以HashMultimap的底層數(shù)據(jù)存儲(chǔ)就是我們的老朋友 HashMap<K, HashSet<V>>
2. 簡(jiǎn)單使用介紹
基本來(lái)講,HashMultimap的使用姿勢(shì)非常簡(jiǎn)單了,下面給出簡(jiǎn)單實(shí)例演示一下,基本上看看就會(huì)了
2.1 容器創(chuàng)建
// 創(chuàng)建一個(gè)默認(rèn)的 HashMap<String, Set<Integer>>,容器的初始化容量與HashMap的默認(rèn)值一樣 HashMultimap<String, Integer> map = HashMultimap.create(); // 當(dāng)我們知道容器的個(gè)數(shù)時(shí),推薦使用下面這種方式, // HashMap 設(shè)置容量為8, 每個(gè)HashSet的容量初始化為16 HashMultimap<String, Integer> map2 = HashMultimap.create(8, 16); // 另外一個(gè)就是基于MultMap來(lái)創(chuàng)建的case了 HashMultimap<String, Integer> map3 = HashMultimap.create(map);
注意上面的第三種實(shí)現(xiàn),需要理解的是 map3.get(key) != map.get(key)
即基于原來(lái)的容器初始化的新容器,其value是一個(gè)新的容器對(duì)象,將之前的value中所有元素,都塞入新的容器中,并不是直接引用就的容器對(duì)象(這么一說(shuō)是不是更想是深拷貝,而不是淺拷貝呢?)
2.2 添加元素
// 添加單個(gè)元素
map.put("hello", 510);
// 添加多個(gè)元素
map.putAll("skill", Arrays.asList(1, 2, 3, 4, 1));注意
- 因?yàn)関alue是HashSet,所以重復(fù)的元素會(huì)忽略
- 塞入重復(fù)的元素會(huì)忽略
- 再次申明,添加重復(fù)的元素會(huì)忽略
(沒(méi)錯(cuò),我就是這里出了問(wèn)題......)
2.3 移除元素
// 移除skill對(duì)應(yīng)的集合中,value=3的元素
map.remove("skill", 3);
// 移除key
map.removeAll("hello");2.4 替換元素
如果我們希望將整個(gè)value都換成一個(gè)新的集合,那么可以使用replaceValue
// 直接替換skill對(duì)應(yīng)的value集合,新的值為 {100, 200, 300}
map.replaceValues("skill", Arrays.asList(100, 200, 300));2.5 獲取元素及遍歷
// 獲取對(duì)應(yīng)的value集合,當(dāng)不存在時(shí),返回空集合(不是null,簡(jiǎn)直是貼心)
Set<Integer> set = map.get("skill");foreach方式的迭代
for (Map.Entry<String, Integer> entry: map.entries()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}注意上面的迭代成員 Map.Entry<String, Integer>,其key依然是HashMap的key,而value則是這個(gè)集合中的沒(méi)一個(gè)元素,比如容器中的值為("skill": [100,200,300])時(shí),此時(shí)輸出如下
skill:200
skill:100
skill:300
2.6 輸出所有的key
// 輸出所有的key, map.keys() // 輸出key集合 map.keySet();
他們兩有啥區(qū)別?看個(gè)實(shí)例
HashMultimap<String, Integer> map = HashMultimap.create();
map.replaceValues("skill", Arrays.asList(100, 200, 300));
System.out.println("keys=" + map.keys());
System.out.println("keySet=" + map.keySet());輸出如下
keys=[skill x 3]
keySet=[skill]
上面這個(gè)skill x 3是什么鬼,實(shí)際上表示skill有三個(gè),返回的容器可以理解為L(zhǎng)ist,不去重
而下面的KeySet()則返回的是個(gè)Set,會(huì)去重
2.7 輸出所有的value
map.values()
通過(guò)上面的再理解這個(gè)就簡(jiǎn)單了,所有的value都合并再一個(gè)List,接下來(lái)我們看一下兩種遍歷方式
HashMultimap<String, Integer> map = HashMultimap.create();
map.putAll("skill", Arrays.asList(100, 200, 300));
map.put("a", 100);
for (Integer v: map.values()) {
System.out.println(v);
}實(shí)際輸出如下
100
100
200
300
3. 小結(jié)
這里主要介紹的是Gauva的容器HashMultimap的數(shù)據(jù)模型及使用姿勢(shì),知識(shí)點(diǎn)相對(duì)來(lái)說(shuō)比較基礎(chǔ),再實(shí)際使用的時(shí)候,請(qǐng)牢記,把它看作是簡(jiǎn)單方便易使用的 HashMap<K, HashSet<V>> 即可,重點(diǎn)注意value中的元素不能重復(fù)即可
那么當(dāng)我們希望value是個(gè)List時(shí),可以怎么整呢?
- 此時(shí)可以使用 LinkedMultiValueMap 來(lái)替代,它的底層數(shù)據(jù)結(jié)構(gòu)實(shí)際就是
HashMap<K, LinkedHashMap<V>> - 使用
ArrayListMultimap也可以,底層數(shù)據(jù)結(jié)構(gòu)為HashMap<K, ArrayList<V>>
最后提一句,guava的這幾個(gè)容器的實(shí)現(xiàn),其源碼閱讀起來(lái)不會(huì)吃力,且設(shè)計(jì)思路也非常典型,比如如果讓我們自己來(lái)基于jdk的基礎(chǔ)容器實(shí)現(xiàn)一個(gè)類似的容器,如何優(yōu)雅的去實(shí)現(xiàn)呢? 這里就給了一個(gè)標(biāo)準(zhǔn)答案,強(qiáng)烈推薦有興趣的小伙伴瞅一下
到此這篇關(guān)于Java項(xiàng)目Guava包 HashMultimap使用及注意事項(xiàng)的文章就介紹到這了,更多相關(guān)java HashMultimap使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突
這篇文章主要介紹了Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突問(wèn)題,通過(guò)注釋掉2.0引入的倆包,直接引入3.0,文中結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-10-10
利用SpringMVC和Ajax實(shí)現(xiàn)文件上傳功能
這篇文章主要為大家詳細(xì)介紹了利用SpringMVC和Ajax實(shí)現(xiàn)文件上傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08
springboot使用com.github.binarywang包實(shí)現(xiàn)微信網(wǎng)頁(yè)上的支付和退款
最近做項(xiàng)目需要實(shí)現(xiàn)在pc端需要實(shí)現(xiàn)微信的支付,本文主要介紹了springboot使用com.github.binarywang包實(shí)現(xiàn)微信網(wǎng)頁(yè)上的支付和退款,具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05
實(shí)例講解Java并發(fā)編程之ThreadLocal類
這篇文章主要介紹了實(shí)例講解Java并發(fā)編程之ThreadLocal類,本文給出了模擬ThreadLocal、實(shí)用ThreadLocal等代碼實(shí)例,需要的朋友可以參考下2015-04-04
Spring FactoriesLoader機(jī)制實(shí)例詳解
這篇文章主要介紹了Spring FactoriesLoader機(jī)制實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
NoHttpResponseException異常解決優(yōu)化HttpClient配置以避免連接問(wèn)題
這篇文章主要為大家介紹了NoHttpResponseException異常解決,優(yōu)化HttpClient配置以避免連接問(wèn)題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
mybatis?foreach傳兩個(gè)參數(shù)批量刪除
這篇文章主要介紹了mybatis?foreach?批量刪除傳兩個(gè)參數(shù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
Spark?集群執(zhí)行任務(wù)失敗的故障處理方法
這篇文章主要為大家介紹了Spark?集群執(zhí)行任務(wù)失敗的故障處理方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02

