1. 程式人生 > 程式設計 >詳解Java8合併兩個Map中元素的正確姿勢

詳解Java8合併兩個Map中元素的正確姿勢

1. 介紹

本入門教程將介紹Java8中如何合併兩個map。

更具體說來,我們將研究不同的合併方案,包括Map含有重複元素的情況。

2. 初始化

我們定義兩個map例項

private static Map<String,Employee> map1 = new HashMap<>();
private static Map<String,Employee> map2 = new HashMap<>();

Employee類

public class Employee {
 
 private Long id;
 private String name;
 
 // 此處省略構造方法,getters,setters方法
}

然後往map中存入一些資料

Employee employee1 = new Employee(1L,"Henry");
map1.put(employee1.getName(),employee1);
Employee employee2 = new Employee(22L,"Annie");
map1.put(employee2.getName(),employee2);
Employee employee3 = new Employee(8L,"John");
map1.put(employee3.getName(),employee3);
 
Employee employee4 = new Employee(2L,"George");
map2.put(employee4.getName(),employee4);
Employee employee5 = new Employee(3L,"Henry");
map2.put(employee5.getName(),employee5);

特別需要注意的是employee1 和 employee5在map中有完全相同的key(name)。

3. Map.merge()

Java8為 java.util.Map介面新增了merge()函式。

merge() 函式的作用是: 如果給定的key之前沒設定value 或者value為null,則將給定的value關聯到這個key上.

否則,通過給定的remaping函式計算的結果來替換其value。如果remapping函式的計算結果為null,將解除此結果。

First,let's construct a new HashMap by copying all the entries from the map1:

首先,我們通過拷貝map1中的元素來構造一個新的HashMap

Map<String,Employee> map3 = new HashMap<>(map1);

然後引入merge函式和合並規則

map3.merge(key,value,(v1,v2) -> new Employee(v1.getId(),v2.getName())

最後對map2進行迭代將其元素合併到map3中

map2.forEach(
 (key,value) -> map3.merge(key,v2.getName())));

執行程式並列印結果如下:

John=Employee{id=8,name='John'}
Annie=Employee{id=22,name='Annie'}
George=Employee{id=2,name='George'}
Henry=Employee{id=1,name='Henry'}

最終,通過結果可以看出,實現了兩個map的合併,對重複的key也合併為同一個元素。

注意最後一個Employee的id來自map1而name來自map2.

原因是我們的merge函式的定義

(v1,v2.getName())

4. Stream.concat()

Java8的Stream API 也為解決該問題提供了較好的解決方案。

首先需要將兩個map合為一個Stream。

Stream combined = Stream.concat(map1.entrySet().stream(),map2.entrySet().stream());

我們需要將entry sets作為引數,然後利用Collectors.toMap():將結果放到新的map中。

Map<String,Employee> result = combined.collect(
 Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));

該方法可以實現map的合併,但是有重複key會報IllegalStateException異常。

為了解決這個問題,我們需要加入lambda表示式merger作為第三個引數

(value1,value2) -> new Employee(value2.getId(),value1.getName())

當檢測到有重複Key時就會用到該lambda表示式。

現在把上面程式碼組合在一起:

Map<String,Employee> result = Stream.concat(map1.entrySet().stream(),map2.entrySet().stream())
 .collect(Collectors.toMap(
 Map.Entry::getKey,Map.Entry::getValue,(value1,value1.getName())));

最終的結果

George=Employee{id=2,name='George'}
John=Employee{id=8,name='Annie'}
Henry=Employee{id=3,name='Henry'}

從結果可以看出重複的key “Henry”將合併為一個新的鍵值對,id取自map2,name取自map1。

5. Stream.of()

通過Stream.of()方法不需要藉助其他stream就可以實現map的合併。

Map<String,Employee> map3 = Stream.of(map1,map2)
 .flatMap(map -> map.entrySet().stream())
 .collect(Collectors.toMap(
 Map.Entry::getKey,v2.getName())));

首先將map1和map2的元素合併為同一個流,然後再轉成map。通過使用v1的id和v2的name來解決重複key的問題。

map3的執行列印結果如下:

6. Simple Streaming

我們還可以藉助stream的管道操作來實現map合併。

Map<String,Employee> map3 = map2.entrySet()
 .stream()
 .collect(Collectors.toMap(
 Map.Entry::getKey,v2.getName()),() -> new HashMap<>(map1)));

結果如下:

{John=Employee{id=8,name='John'},
Annie=Employee{id=22,name='Annie'},
George=Employee{id=2,name='George'},
Henry=Employee{id=1,name='Henry'}}

7. StreamEx

我們還可以使Stream API 的增強庫

Map<String,Employee> map3 = EntryStream.of(map1)
 .append(EntryStream.of(map2))
 .toMap((e1,e2) -> e1);

注意 (e1,e2) -> e1 表示式來處理重複key的問題,如果沒有該表示式依然會報IllegalStateException異常。

結果:

{George=Employee{id=2,
John=Employee{id=8,name='Henry'}}

8 總結

本文使用了Map.merge(),Stream API,StreamEx 庫實現map的合併。

英文原文地址:https://www.baeldung.com/java-merge-maps

到此這篇關於詳解Java8合併兩個Map中元素的正確姿勢的文章就介紹到這了,更多相關Java8合併Map中元素內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!