Java?Multimap實(shí)現(xiàn)類與操作的具體示例
一、Multimap 概述
Multimap 是 Google Guava 庫(kù)中提供的一種集合類型,它擴(kuò)展了傳統(tǒng)的 Map 概念,允許一個(gè)鍵對(duì)應(yīng)多個(gè)值。與標(biāo)準(zhǔn)的 Map<K, List<V>>
或 Map<K, Set<V>>
相比,Multimap 提供了更簡(jiǎn)潔的 API 和更強(qiáng)大的功能。
Multimap 主要特點(diǎn):
- 一個(gè)鍵可以映射到多個(gè)值
- 避免了手動(dòng)管理值集合的麻煩
- 提供了豐富的視圖集合
- 支持不可變實(shí)現(xiàn)
二、Multimap 實(shí)現(xiàn)類
Guava 提供了多種 Multimap 實(shí)現(xiàn),每種實(shí)現(xiàn)都有不同的特性和使用場(chǎng)景。
1. ListMultimap 系列
特點(diǎn):值以 List 形式存儲(chǔ),允許重復(fù)值,保留插入順序
實(shí)現(xiàn)類 | 描述 | 是否線程安全 |
---|---|---|
ArrayListMultimap | 使用 ArrayList 作為值集合 | 否 |
LinkedListMultimap | 使用 LinkedList 作為值集合 | 否 |
ImmutableListMultimap | 不可變實(shí)現(xiàn) | 是 |
2. SetMultimap 系列
特點(diǎn):值以 Set 形式存儲(chǔ),不允許重復(fù)值
實(shí)現(xiàn)類 | 描述 | 是否線程安全 |
---|---|---|
HashMultimap | 使用 HashSet 作為值集合 | 否 |
LinkedHashMultimap | 使用 LinkedHashSet 作為值集合,保留插入順序 | 否 |
TreeMultimap | 使用 TreeSet 作為值集合,按鍵和值排序 | 否 |
ImmutableSetMultimap | 不可變實(shí)現(xiàn) | 是 |
3. 其他實(shí)現(xiàn)
實(shí)現(xiàn)類 | 描述 | 是否線程安全 |
---|---|---|
Multimaps.synchronizedMultimap | 同步包裝器,使任何 Multimap 線程安全 | 是 |
Multimaps.unmodifiableMultimap | 不可修改視圖 | 是 |
三、Multimap 基本操作示例
1. 創(chuàng)建 Multimap
// 創(chuàng)建ArrayListMultimap ListMultimap<String, String> listMultimap = ArrayListMultimap.create(); // 創(chuàng)建HashMultimap SetMultimap<String, Integer> setMultimap = HashMultimap.create(); // 創(chuàng)建不可變Multimap ImmutableListMultimap<String, String> immutableMultimap = ImmutableListMultimap.of( "key1", "value1", "key1", "value2", "key2", "value3" );
2. 添加元素
ListMultimap<String, String> multimap = ArrayListMultimap.create(); // 添加單個(gè)元素 multimap.put("fruit", "apple"); multimap.put("fruit", "banana"); multimap.put("fruit", "orange"); multimap.put("vegetable", "carrot"); // 添加多個(gè)元素 multimap.putAll("fruit", Arrays.asList("pear", "grape")); multimap.putAll("vegetable", Arrays.asList("potato", "tomato"));
3. 獲取元素
// 獲取某個(gè)鍵的所有值 List<String> fruits = multimap.get("fruit"); // [apple, banana, orange, pear, grape] // 獲取第一個(gè)值 String firstFruit = multimap.get("fruit").get(0); // apple // 檢查鍵是否存在 boolean hasFruit = multimap.containsKey("fruit"); // true // 檢查鍵值對(duì)是否存在 boolean hasApple = multimap.containsEntry("fruit", "apple"); // true
4. 刪除元素
// 刪除鍵的所有值 multimap.removeAll("fruit"); // 返回被刪除的值列表 // 刪除特定鍵值對(duì) multimap.remove("vegetable", "tomato"); // 返回boolean表示是否刪除成功 // 清空所有元素 multimap.clear();
5. 視圖操作
// 獲取所有鍵的集合(去重) Set<String> keys = multimap.keySet(); // 獲取所有值的集合(不去重) Collection<String> values = multimap.values(); // 獲取鍵值對(duì)集合 Collection<Map.Entry<String, String>> entries = multimap.entries(); // 將Multimap轉(zhuǎn)換為Map<K, Collection<V>> Map<String, Collection<String>> mapView = multimap.asMap();
四、不同實(shí)現(xiàn)類的具體示例
1. ArrayListMultimap 示例
// 創(chuàng)建ArrayListMultimap ListMultimap<String, Integer> scores = ArrayListMultimap.create(); // 添加元素 scores.put("Alice", 90); scores.put("Alice", 85); scores.put("Bob", 75); scores.put("Bob", 80); scores.put("Bob", 82); // 獲取元素 List<Integer> aliceScores = scores.get("Alice"); // [90, 85] List<Integer> bobScores = scores.get("Bob"); // [75, 80, 82] // 允許重復(fù)值 scores.put("Alice", 90); List<Integer> newAliceScores = scores.get("Alice"); // [90, 85, 90]
2. HashMultimap 示例
// 創(chuàng)建HashMultimap SetMultimap<String, String> tags = HashMultimap.create(); // 添加元素 tags.put("article1", "tech"); tags.put("article1", "java"); tags.put("article1", "programming"); tags.put("article2", "design"); tags.put("article2", "ui"); // 嘗試添加重復(fù)值 tags.put("article1", "java"); // 不會(huì)有任何效果 // 獲取元素 Set<String> article1Tags = tags.get("article1"); // [tech, java, programming] Set<String> article2Tags = tags.get("article2"); // [design, ui]
3. TreeMultimap 示例
// 創(chuàng)建TreeMultimap(按鍵和值排序) TreeMultimap<String, Integer> sortedScores = TreeMultimap.create(); // 添加元素(亂序) sortedScores.put("Bob", 80); sortedScores.put("Alice", 90); sortedScores.put("Bob", 75); sortedScores.put("Alice", 85); // 獲取元素(自動(dòng)排序) SortedSet<Integer> aliceSortedScores = sortedScores.get("Alice"); // [85, 90] SortedSet<Integer> bobSortedScores = sortedScores.get("Bob"); // [75, 80] // 整個(gè)Multimap也是按鍵排序的 System.out.println(sortedScores); // {Alice=[85, 90], Bob=[75, 80]}
4. ImmutableListMultimap 示例
// 創(chuàng)建不可變Multimap ImmutableListMultimap<String, String> immutableMap = ImmutableListMultimap.<String, String>builder() .put("colors", "red") .put("colors", "green") .put("colors", "blue") .put("shapes", "circle") .put("shapes", "square") .build(); // 嘗試修改會(huì)拋出UnsupportedOperationException // immutableMap.put("colors", "yellow"); // 錯(cuò)誤! // 安全地獲取數(shù)據(jù) List<String> colors = immutableMap.get("colors"); // [red, green, blue]
五、高級(jí)操作與工具方法
1. 使用 Multimaps 工具類
// 從Map<K, Collection<V>>創(chuàng)建Multimap Map<String, List<Integer>> map = new HashMap<>(); map.put("a", Arrays.asList(1, 2, 3)); map.put("b", Arrays.asList(4, 5)); ListMultimap<String, Integer> multimap = Multimaps.forMap(map); // 轉(zhuǎn)換Multimap的值類型 ListMultimap<String, String> stringMultimap = ArrayListMultimap.create(); stringMultimap.put("key", "1"); stringMultimap.put("key", "2"); ListMultimap<String, Integer> intMultimap = Multimaps.transformValues(stringMultimap, Integer::valueOf); // 反轉(zhuǎn)Multimap(鍵值互換) SetMultimap<Integer, String> inverted = Multimaps.invertFrom(stringMultimap, HashMultimap.create());
2. 過(guò)濾操作
ListMultimap<String, Integer> scores = ArrayListMultimap.create(); scores.put("Alice", 90); scores.put("Alice", 85); scores.put("Bob", 75); scores.put("Bob", 80); // 過(guò)濾出分?jǐn)?shù)大于80的條目 Multimap<String, Integer> highScores = Multimaps.filterEntries(scores, entry -> entry.getValue() > 80); System.out.println(highScores); // {Alice=[90, 85]}
3. 同步包裝
ListMultimap<String, String> unsafeMultimap = ArrayListMultimap.create(); // 創(chuàng)建線程安全版本 ListMultimap<String, String> safeMultimap = Multimaps.synchronizedListMultimap(unsafeMultimap); // 現(xiàn)在可以安全地在多線程環(huán)境中使用 safeMultimap.put("key", "value");
六、性能比較與選擇指南
實(shí)現(xiàn)類 | 鍵存儲(chǔ) | 值存儲(chǔ) | 允許重復(fù)值 | 順序保證 | 典型用途 |
---|---|---|---|---|---|
ArrayListMultimap | HashMap | ArrayList | 是 | 插入順序 | 需要保留插入順序且允許重復(fù)值的場(chǎng)景 |
LinkedListMultimap | LinkedHashMap | LinkedList | 是 | 插入順序 | 需要頻繁在中間插入/刪除的場(chǎng)景 |
HashMultimap | HashMap | HashSet | 否 | 無(wú) | 需要快速查找且不需要重復(fù)值的場(chǎng)景 |
LinkedHashMultimap | LinkedHashMap | LinkedHashSet | 否 | 插入順序 | 需要保留插入順序且不允許重復(fù)值的場(chǎng)景 |
TreeMultimap | TreeMap | TreeSet | 否 | 排序順序 | 需要按鍵和值排序的場(chǎng)景 |
ImmutableListMultimap | 不可變 | 不可變 | 是 | 構(gòu)造順序 | 需要不可變集合的場(chǎng)景 |
ImmutableSetMultimap | 不可變 | 不可變 | 否 | 構(gòu)造順序 | 需要不可變集合且不允許重復(fù)值的場(chǎng)景 |
選擇建議:
- 如果需要允許重復(fù)值 - 選擇 ListMultimap 實(shí)現(xiàn)
- 如果需要快速查找且不允許重復(fù)值 - 選擇 SetMultimap 實(shí)現(xiàn)
- 如果需要排序功能 - 選擇 TreeMultimap
- 如果需要線程安全 - 使用不可變實(shí)現(xiàn)或同步包裝器
- 如果數(shù)據(jù)不常變化 - 優(yōu)先考慮不可變實(shí)現(xiàn)
七、常見問(wèn)題解答
Q1: Multimap 和 Map<K, List> 有什么區(qū)別?
A1: 主要區(qū)別在于:
- Multimap 提供了更簡(jiǎn)潔的 API,不需要手動(dòng)管理值集合
- Multimap 提供了豐富的視圖方法(如 entries(), keys(), values())
- Multimap 隱藏了實(shí)現(xiàn)細(xì)節(jié),可以更靈活地切換底層實(shí)現(xiàn)
- Multimap 的方法更直觀,如 put() 直接添加元素而不需要先檢查是否存在集合
Q2: 如何將 Multimap 轉(zhuǎn)換為傳統(tǒng)的 Map?
A2: 可以使用 asMap() 方法:
ListMultimap<String, String> multimap = ArrayListMultimap.create(); multimap.put("key", "value1"); multimap.put("key", "value2"); Map<String, Collection<String>> map = multimap.asMap();
Q3: Multimap 是線程安全的嗎?
A3: 大多數(shù) Multimap 實(shí)現(xiàn)不是線程安全的,除了:
- 不可變實(shí)現(xiàn)(ImmutableListMultimap, ImmutableSetMultimap)
- 使用 Multimaps.synchronizedMultimap() 包裝的 Multimap
Q4: 如何統(tǒng)計(jì) Multimap 中每個(gè)鍵對(duì)應(yīng)的值數(shù)量?
A4: 可以使用 Multimap 的 keys() 方法結(jié)合 Multisets:
ListMultimap<String, String> multimap = ArrayListMultimap.create(); // 添加元素... Multiset<String> counts = HashMultiset.create(multimap.keys()); System.out.println(counts); // 顯示每個(gè)鍵的出現(xiàn)次數(shù)
八、總結(jié)
Guava 的 Multimap 提供了一種優(yōu)雅的方式來(lái)處理鍵到多個(gè)值的映射關(guān)系,比傳統(tǒng)的 Map<K, Collection<V>>
更加方便和強(qiáng)大。通過(guò)選擇合適的實(shí)現(xiàn)類,可以滿足各種不同的業(yè)務(wù)需求,包括是否需要允許重復(fù)值、是否需要保持順序、是否需要排序等功能。
在實(shí)際開發(fā)中,Multimap 特別適用于以下場(chǎng)景:
- 標(biāo)簽系統(tǒng)(一個(gè)項(xiàng)目有多個(gè)標(biāo)簽)
- 學(xué)生成績(jī)記錄(一個(gè)學(xué)生有多門成績(jī))
- 反向索引(一個(gè)單詞出現(xiàn)在多個(gè)文檔中)
- 分組統(tǒng)計(jì)(按類別分組記錄)
掌握 Multimap 的使用可以顯著簡(jiǎn)化代碼,提高開發(fā)效率,是 Java 開發(fā)者工具箱中不可或缺的工具之一。
到此這篇關(guān)于Java Multimap實(shí)現(xiàn)類與操作具體示例的文章就介紹到這了,更多相關(guān)Java Multimap類操作示例內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring核心容器之ApplicationContext上下文啟動(dòng)準(zhǔn)備詳解
這篇文章主要介紹了Spring核心容器之ApplicationContext上下文啟動(dòng)準(zhǔn)備詳解,ApplicationContext 繼承自 BeanFactory ,其不僅包含 BeanFactory 所有功能,還擴(kuò)展了容器功能,需要的朋友可以參考下2023-11-11Java 8對(duì)LinkedHashSet元素進(jìn)行排序的操作方法
LinkedHashSet 是 Java 集合框架中的一個(gè)類,它繼承自 HashSet,并實(shí)現(xiàn)了 Set 接口,然而,LinkedHashSet 不支持元素的排序,它僅僅保持插入順序,所以本文給大家介紹了Java 8 如何對(duì) LinkedHashSet 元素進(jìn)行排序,需要的朋友可以參考下2024-11-11IDEA?2022?中的Lombok?使用基礎(chǔ)教程
? Lombok是使用java編寫的一款開源類庫(kù)。其主作用是使用注解來(lái)代替一些具有格式固定,沒(méi)有過(guò)多技術(shù)含量的編碼工作,這篇文章主要介紹了IDEA?2022?中的Lombok?使用基礎(chǔ)教程,需要的朋友可以參考下2022-12-12IDEA實(shí)現(xiàn)遠(yuǎn)程調(diào)試步驟詳解
這篇文章主要介紹了IDEA實(shí)現(xiàn)遠(yuǎn)程調(diào)試步驟詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09hystrix配置中Apollo與Archaius對(duì)比分析
這篇文章主要為大家介紹了hystrix的配置中Apollo與Archaius對(duì)比分析,并為大家解答在hystrix的配置中有了Apollo是否還需要Archaius這一問(wèn)題詳解2022-02-02使用okhttp替換Feign默認(rèn)Client的操作
這篇文章主要介紹了使用okhttp替換Feign默認(rèn)Client的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02java中的equals()和toString()方法實(shí)例詳解
這篇文章主要介紹了java中的equals()和toString()方法實(shí)例詳解的相關(guān)資料,這里舉例說(shuō)明,并附實(shí)例代碼,和實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-11-11