在 Java 中,如何為用作 HashMap 值的 ArrayList 新增值
1. 概述
在本教程中,我們將探討如何在 Java 中使用Map來儲存單一鍵的多個值。一種方法是使用List作為Map值類型,並將元素加入其中,資料結構的形式為Map<K, List<V>> 。
我們將示範如何使用HashMap和ArrayList ,當然您也可以使用任何其他Map和List實作。此外,我們還可以使用支援多值資料結構的外部函式庫。我們將介紹三種實作此方法的方式,包括如何安全地將多個值加到同一個鍵。
2. 手動處理鍵、值和清單元素
第一種方法,我們將自行處理所有事情,手動新增金鑰:
public static Map<String, List> addKeyManually(Map<String, List> map, String key, String value) {
if (!map.containsKey(key)) {
map.put(key, new ArrayList());
}
map.get(key).add(value);
return map;
}
我們正在手動檢查HashMap是否包含我們嘗試新增的key ,以確保存在有效的ArrayList來儲存我們的值。如果該鍵不包含有效的List ,我們將使用put方法為字典指派一個 List,即map.put(key, new ArrayList<>()) 。
一旦我們知道映射中存在給定key的有效List ,**我們就可以手動向List.**我們可以使用map.get(key) ` 方法get此List 。然後,對於該List ,我們可以使用map.get(key).add(value)方法add value 。
我們可以直接對空的HashMap使用此方法:
Map<String, List<String>> map = new HashMap<>();
ArrayListInHashMap.addKeyManually(map, K1, K1_V1);
ArrayListInHashMap.addKeyManually(map, K1, K1_V2);
ArrayListInHashMap.addKeyManually(map, K2, K2_V1);
這將會建構一個形如{key1=[key1_value1, key1_value2], key2=[key2_value1]}.我們可以看到,並非每個List都需要包含相同數量的值。
這個解決方案有點冗長,但它非常通用,因為我們可以在任何 Java 版本(甚至是 Java 5)中使用它,而且它有助於理解此實作的基本邏輯。
然而,這個版本的計算效率不如以下方案。這裡我們需要執行兩到三次查找。其中兩個查找分別透過containsKey和get方法完成。如果執行put操作,則可能需要第三次查找。我們可以透過新增null檢查來最佳化程式碼,從而避免同時呼叫containsKey和 `get` 方法。 get 。
3. 利用computeIfAbsent方法
從 Java 8 開始,我們可以使用Map介面的computeIfAbsent方法。我們可以透過傳入key ,以及一個用於獲取新值並將其插入到映射中的映射(如果該key不存在),來使用此computeIfAbsent方法檢索映射中給定鍵的key :
public static Map<String, List> addKeyWithComputeIfAbsent(
Map<String, List> map, String key, String value) {
map.computeIfAbsent(key, k -> new ArrayList()).add(value);
return map;
}
透過使用computeIfAbsent我們不需要手動執行containsKey檢查,因為初始化時會自動執行此檢查。
我們可以再次建構與之前相同的地圖:
Map<String, List<String>> map = new HashMap<>;
ArrayListInHashMap.addKeyWithComputeIfAbsent(map, K1, K1_V1);
ArrayListInHashMap.addKeyWithComputeIfAbsent(map, K1, K1_V2);
ArrayListInHashMap.addKeyWithComputeIfAbsent(map, K2, K2_V1);
這段程式碼的主要優勢在於,我們使用computeIfAbsent,而之前這些操作都是手動完成的。 `computeIfAbsent` computeIfAbsent只需一次查找,而先前的版本則需要兩到三次查找,因為它只查找一次鍵,並在鍵位於該記憶體位置時就決定下一步操作。但是, computeIfAbsent函數需要 Java 8 或更高版本才能使用。
4. 使用外部函式庫
當然,在HashMap中為同一個鍵儲存多個值是我們經常會遇到的問題。因此,我們可以藉助外部庫提供的資料結構來解決這個問題。我們將介紹三種最常用的資料結構,以便我們可以直接使用程式碼庫中已經使用的資料結構。
4.1. 來自 Apache Commons Collections 的MultiValuedMap
Apache Commons Collections 庫提供了MultiValuedMap接口,讓我們可以為單個鍵儲存多個值:
public static MultiValuedMap<String, String> addKeyToApacheMultiValuedMap(
MultiValuedMap<String, String> map, String key, String value) {
map.put(key, value);
return map;
}
這看起來和之前的方法類似,但我們不需要手動管理ArrayList部分,只需呼叫put方法即可,它會自動處理所有操作。此外,還有許多其他輔助方法可以幫助我們輕鬆地與地圖內容互動。
4.2. Spring 中的LinkedMultiValueMap
另一個支援單一鍵對應多個值的流行庫是 Spring。它提供了LinkedMultiValueMap介面來實現我們的目標:
public static MultiValueMap<String, String> addKeyToSpringLinkedMultiValueMap(
MultiValueMap<String, String> map, String key, String value) {
map.add(key, value);
return map;
}
我們可以看到, map類型宣告使用了兩個字串, MultiValueMap<String, String> ,因為它是一個 ` LinkedMultiValueMap ,可以處理具有相同鍵的值。之前,我們使用的是 ` HashMap ,其中每個鍵都是一個String ,對應的值是一個List<String> `。
4.3. 來自 Google Guava 的Multimap
最後,另一個流行的庫是谷歌的 Guava,它提供了Multimap接口,可以創建一個鍵存儲多個值的映射:
public static Multimap<String, String> addKeyToGuavaMultimap(
Multimap<String, String> map, String key, String value) {
map.put(key, value);
return map;
}
我們發現所有外部函式庫的語法都非常相似。 Guava 庫非常高效,並且被廣泛應用於許多大型專案中,因此,如果我們已經在程式碼庫中使用它,那麼我們可能可以直接獲得地圖功能的支援。
5. 結論
本文討論了在類似映射的結構中,如何為單一鍵設定多個值。我們介紹了三種解決方案,您可以根據程式碼和需求進行選擇。
第一種方案詳細描述了處理過程的每一步,即手動處理分配給 HashMap 中每個鍵的ArrayList中的值HashMap.此方案相容於所有 Java 版本,但略顯冗長。此外,根據我們的實作方式,可能會遇到一些較新函式庫所不需要的計算開銷。
第二種方法可以利用一些較新的技術。它仍然使用一個Map和一個List來儲存每個鍵的多個值,但我們依賴一些方法來自動化介面的使用並執行檢查。
最後,第三種解決方案著重於外部庫中實現的接口,例如 Apache Commons Collections 中的MultiValuedMap 、Spring 中的LinkedMultiValueMap和 Google Guava 中的Multimap 。如果我們已經在程式碼庫中使用這些庫中的任何一個,就可以利用這些結構來簡化程式碼。