Java?Multimap實(shí)現(xiàn)類與操作的具體示例
一、Multimap 概述
Multimap 是 Google Guava 庫中提供的一種集合類型,它擴(kuò)展了傳統(tǒng)的 Map 概念,允許一個(gè)鍵對應(yīng)多個(gè)值。與標(biāo)準(zhǔn)的 Map<K, List<V>> 或 Map<K, Set<V>> 相比,Multimap 提供了更簡潔的 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)都有不同的特性和使用場景。
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
// 檢查鍵值對是否存在
boolean hasApple = multimap.containsEntry("fruit", "apple"); // true
4. 刪除元素
// 刪除鍵的所有值
multimap.removeAll("fruit"); // 返回被刪除的值列表
// 刪除特定鍵值對
multimap.remove("vegetable", "tomato"); // 返回boolean表示是否刪除成功
// 清空所有元素
multimap.clear();
5. 視圖操作
// 獲取所有鍵的集合(去重) Set<String> keys = multimap.keySet(); // 獲取所有值的集合(不去重) Collection<String> values = multimap.values(); // 獲取鍵值對集合 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]
五、高級操作與工具方法
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. 過濾操作
ListMultimap<String, Integer> scores = ArrayListMultimap.create();
scores.put("Alice", 90);
scores.put("Alice", 85);
scores.put("Bob", 75);
scores.put("Bob", 80);
// 過濾出分?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ù)值的場景 |
| LinkedListMultimap | LinkedHashMap | LinkedList | 是 | 插入順序 | 需要頻繁在中間插入/刪除的場景 |
| HashMultimap | HashMap | HashSet | 否 | 無 | 需要快速查找且不需要重復(fù)值的場景 |
| LinkedHashMultimap | LinkedHashMap | LinkedHashSet | 否 | 插入順序 | 需要保留插入順序且不允許重復(fù)值的場景 |
| TreeMultimap | TreeMap | TreeSet | 否 | 排序順序 | 需要按鍵和值排序的場景 |
| ImmutableListMultimap | 不可變 | 不可變 | 是 | 構(gòu)造順序 | 需要不可變集合的場景 |
| ImmutableSetMultimap | 不可變 | 不可變 | 否 | 構(gòu)造順序 | 需要不可變集合且不允許重復(fù)值的場景 |
選擇建議:
- 如果需要允許重復(fù)值 - 選擇 ListMultimap 實(shí)現(xiàn)
- 如果需要快速查找且不允許重復(fù)值 - 選擇 SetMultimap 實(shí)現(xiàn)
- 如果需要排序功能 - 選擇 TreeMultimap
- 如果需要線程安全 - 使用不可變實(shí)現(xiàn)或同步包裝器
- 如果數(shù)據(jù)不常變化 - 優(yōu)先考慮不可變實(shí)現(xiàn)
七、常見問題解答
Q1: Multimap 和 Map<K, List> 有什么區(qū)別?
A1: 主要區(qū)別在于:
- Multimap 提供了更簡潔的 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è)鍵對應(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)雅的方式來處理鍵到多個(gè)值的映射關(guān)系,比傳統(tǒng)的 Map<K, Collection<V>> 更加方便和強(qiáng)大。通過選擇合適的實(shí)現(xiàn)類,可以滿足各種不同的業(yè)務(wù)需求,包括是否需要允許重復(fù)值、是否需要保持順序、是否需要排序等功能。
在實(shí)際開發(fā)中,Multimap 特別適用于以下場景:
- 標(biāo)簽系統(tǒng)(一個(gè)項(xiàng)目有多個(gè)標(biāo)簽)
- 學(xué)生成績記錄(一個(gè)學(xué)生有多門成績)
- 反向索引(一個(gè)單詞出現(xiàn)在多個(gè)文檔中)
- 分組統(tǒng)計(jì)(按類別分組記錄)
掌握 Multimap 的使用可以顯著簡化代碼,提高開發(fā)效率,是 Java 開發(fā)者工具箱中不可或缺的工具之一。
到此這篇關(guān)于Java Multimap實(shí)現(xiàn)類與操作具體示例的文章就介紹到這了,更多相關(guān)Java Multimap類操作示例內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring核心容器之ApplicationContext上下文啟動(dòng)準(zhǔn)備詳解
這篇文章主要介紹了Spring核心容器之ApplicationContext上下文啟動(dòng)準(zhǔn)備詳解,ApplicationContext 繼承自 BeanFactory ,其不僅包含 BeanFactory 所有功能,還擴(kuò)展了容器功能,需要的朋友可以參考下2023-11-11
Java 8對LinkedHashSet元素進(jìn)行排序的操作方法
LinkedHashSet 是 Java 集合框架中的一個(gè)類,它繼承自 HashSet,并實(shí)現(xiàn)了 Set 接口,然而,LinkedHashSet 不支持元素的排序,它僅僅保持插入順序,所以本文給大家介紹了Java 8 如何對 LinkedHashSet 元素進(jìn)行排序,需要的朋友可以參考下2024-11-11
IDEA?2022?中的Lombok?使用基礎(chǔ)教程
? Lombok是使用java編寫的一款開源類庫。其主作用是使用注解來代替一些具有格式固定,沒有過多技術(shù)含量的編碼工作,這篇文章主要介紹了IDEA?2022?中的Lombok?使用基礎(chǔ)教程,需要的朋友可以參考下2022-12-12
IDEA實(shí)現(xiàn)遠(yuǎn)程調(diào)試步驟詳解
這篇文章主要介紹了IDEA實(shí)現(xiàn)遠(yuǎn)程調(diào)試步驟詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
使用okhttp替換Feign默認(rèn)Client的操作
這篇文章主要介紹了使用okhttp替換Feign默認(rèn)Client的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
java中的equals()和toString()方法實(shí)例詳解
這篇文章主要介紹了java中的equals()和toString()方法實(shí)例詳解的相關(guān)資料,這里舉例說明,并附實(shí)例代碼,和實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-11-11

