Java如何在Map中存放重復(fù)key
如何在Map中存放重復(fù)key
1.概述
本文介紹幾種處理Map中一個(gè)key對(duì)多個(gè)value的方法。在JDK標(biāo)準(zhǔn)Map實(shí)現(xiàn)中當(dāng)我們嘗試在一個(gè)key下插入多個(gè)value,那么后續(xù)的value會(huì)覆蓋前面的value。
Map<String, String> map = new HashMap<>(); assertThat(map.put("key1", "value1")).isEqualTo(null); assertThat(map.put("key1", "value2")).isEqualTo("value1"); assertThat(map.get("key1")).isEqualTo("value2");
2.將集合作為Value
當(dāng)要處理一個(gè)key對(duì)多個(gè)value的情況,可以將所有value存放在一個(gè)集合中。
Map<String, List<String>> map = new HashMap<>(); List<String> list = new ArrayList<>(); map.put("key1", list); map.get("key1").add("value1"); map.get("key1").add("value2"); ?? assertThat(map.get("key1").get(0)).isEqualTo("value1"); assertThat(map.get("key1").get(1)).isEqualTo("value2");
這種方式處理有多種缺點(diǎn)并且容易產(chǎn)生錯(cuò)誤。我們需要為每個(gè)key創(chuàng)建一個(gè)集合,同時(shí)檢查集合是否存在并添加或刪除值,在Java 8中可以利用compute()方法來簡(jiǎn)化代碼。
Map<String, List<String>> map = new HashMap<>(); map.computeIfAbsent("key1", k -> new ArrayList<>()).add("value1"); map.computeIfAbsent("key1", k -> new ArrayList<>()).add("value2"); ? assertThat(map.get("key1").get(0)).isEqualTo("value1"); assertThat(map.get("key1").get(1)).isEqualTo("value2");
3.使用Apache Commons Collections
添加依賴
<dependency> ? <groupId>org.apache.commons</groupId> ? <artifactId>commons-collections4</artifactId> ? <version>4.1</version> </dependency>
3.1 MutiMap
org.apache.commons.collections4.MultiMap接口定義了一個(gè)Map,每個(gè)key對(duì)應(yīng)一個(gè)集合。
MultiMap<String, String> map = new MultiValueMap<>(); map.put("key1", "value1"); map.put("key1", "value2"); assertThat((Collection<String>) map.get("key1")) ? .contains("value1", "value2");
這個(gè)類非線程安全,4.1版本中已經(jīng)廢棄。
3.2 MultiValuedMap
org.apache.commons.collections4.MultiValuedMap這個(gè)接口有多種實(shí)現(xiàn),如ArrayListValuedHashMap與HashSetValuedHashMap。
使用方式如下:
MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>(); map.put("key1", "value1"); map.put("key1", "value2"); map.put("key1", "value2"); assertThat((Collection<String>) map.get("key1")) ? .containsExactly("value1", "value2", "value2"); MultiValuedMap<String, String> map = new HashSetValuedHashMap<>(); map.put("key1", "value1"); map.put("key1", "value1"); assertThat((Collection<String>) map.get("key1")) ? .containsExactly("value1");
若不希望value重復(fù)那么可以使用HashSetValuedHashMap
MultiValuedMap<String, String> map = new HashSetValuedHashMap<>(); map.put("key1", "value1"); map.put("key1", "value1"); assertThat((Collection<String>) map.get("key1")) ? .containsExactly("value1");
但ArrayListValuedHashMap,HashSetValuedHashMap及HashSetValuedHashMap都不是線程安全的。為了線程安全可以使用UnmodifiableMultiValuedMap。
@Test(expected = UnsupportedOperationException.class) public void givenUnmodifiableMultiValuedMap_whenInserting_thenThrowingException() { ? ? MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>(); ? ? map.put("key1", "value1"); ? ? map.put("key1", "value2"); ? ? MultiValuedMap<String, String> immutableMap = ? ? ? MultiMapUtils.unmodifiableMultiValuedMap(map); ? ? immutableMap.put("key1", "value3"); }
4.Guava Multimap
<dependency> ? <groupId>com.google.guava</groupId> ? <artifactId>guava</artifactId> ? <version>23.0</version> </dependency>
4.1 LinkedHashMultimap
這個(gè)類按插入順序存放插入元素
Multimap<String, String> map = LinkedHashMultimap.create(); map.put("key1", "value3"); map.put("key1", "value1"); map.put("key1", "value2"); assertThat((Collection<String>) map.get("key1")) ? .containsExactly("value3", "value1", "value2");
4.2 TreeMultimap
這個(gè)類按可以按自然序訪問插入的元素
Multimap<String, String> map = TreeMultimap.create(); map.put("key1", "value3"); map.put("key1", "value1"); map.put("key1", "value2"); assertThat((Collection<String>) map.get("key1")) ? .containsExactly("value1", "value2", "value3");
5.自定義MultiMap
如果使用Guava,那么還可以使用Multimap.newMultimap()來定制我們的Map。
小結(jié):一對(duì)多思路就是通過集合來存儲(chǔ)元素,guava和apache collection為我們提供了現(xiàn)成的工具,如果想自定義還可以使用guava提供的擴(kuò)展方法來實(shí)現(xiàn)。
Map出現(xiàn)重復(fù)Key值疊加到上一個(gè)key中
Map出現(xiàn)重復(fù)Key值將下一個(gè)key值疊加在上一個(gè)key值中
List<Map<String, Object>> list = new ArrayList<>(); //模擬數(shù)據(jù)庫數(shù)據(jù) for (int i = 0; i < 10; i++) { Map<String, Object> map = new HashMap<>(); map.put("id", i); map.put("name", "張三" + i); if (i < 10 - 1) { map.put("pid", 2); } else { map.put("pid", 3); } list.add(map); } //運(yùn)用map中的containsKey方法 Map<String, Object> map1 = new HashMap<>(); for (Map map2 : list) { List<Object> list1 = new ArrayList<>(); String pid = map2.get("pid") + ""; //如果是重復(fù)的那么就進(jìn)行疊加操作 if (map1.containsKey(pid)) { list1 = (List<Object>) map1.get(pid); } list1.add(map2); map1.put(map2.get("pid") + "", list1); } System.out.println(map1); }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
IntelliJ IDEA的build path設(shè)置方法
這篇文章主要介紹了IntelliJ IDEA的build path設(shè)置方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04IntelliJ IDEA 2020.3 重大特性(新功能一覽)
這篇文章主要介紹了IntelliJ IDEA 2020.3 重大特性(新功能一覽),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12教你通過B+Tree平衡多叉樹理解InnoDB引擎的聚集和非聚集索引
大家都知道B+Tree是從二叉樹演化而來,在這之前我們來先了解二叉樹、平衡二叉樹、平衡多叉樹,這篇文章主要介紹了通過B+Tree平衡多叉樹理解InnoDB引擎的聚集和非聚集索引,需要的朋友可以參考下2022-01-01淺談Java中ThreadLocal內(nèi)存泄露的原因及處理方式
內(nèi)存泄漏就是我們申請(qǐng)了內(nèi)存,但是該內(nèi)存一直無法釋放,就會(huì)導(dǎo)致內(nèi)存溢出問題,本文詳細(xì)的介紹了ThreadLocal內(nèi)存泄露的原因及處理方式,感興趣的可以了解一下2023-05-05java 用遞歸獲取一個(gè)目錄下的所有文件路徑的小例子
還是日志的問題,log4j生成的日志文件,自動(dòng)保存到月份所在的文件夾中,需要獲取到所有的日志文件,包括文件夾2013-09-09