詳解Java8合并兩個(gè)Map中元素的正確姿勢(shì)
1. 介紹
本入門教程將介紹Java8中如何合并兩個(gè)map。
更具體說(shuō)來(lái),我們將研究不同的合并方案,包括Map含有重復(fù)元素的情況。
2. 初始化
我們定義兩個(gè)map實(shí)例
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; // 此處省略構(gòu)造方法, getters, setters方法 }
然后往map中存入一些數(shù)據(jù)
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()函數(shù)。
merge() 函數(shù)的作用是: 如果給定的key之前沒(méi)設(shè)置value 或者value為null, 則將給定的value關(guān)聯(lián)到這個(gè)key上.
否則,通過(guò)給定的remaping函數(shù)計(jì)算的結(jié)果來(lái)替換其value。如果remapping函數(shù)的計(jì)算結(jié)果為null,將解除此結(jié)果。
First, let's construct a new HashMap by copying all the entries from the map1:
首先,我們通過(guò)拷貝map1中的元素來(lái)構(gòu)造一個(gè)新的HashMap
Map<String, Employee> map3 = new HashMap<>(map1);
然后引入merge函數(shù)和合并規(guī)則
map3.merge(key, value, (v1, v2) -> new Employee(v1.getId(),v2.getName())
最后對(duì)map2進(jìn)行迭代將其元素合并到map3中
map2.forEach( (key, value) -> map3.merge(key, value, (v1, v2) -> new Employee(v1.getId(),v2.getName())));
運(yùn)行程序并打印結(jié)果如下:
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
Henry=Employee{id=1, name='Henry'}
最終,通過(guò)結(jié)果可以看出,實(shí)現(xiàn)了兩個(gè)map的合并,對(duì)重復(fù)的key也合并為同一個(gè)元素。
注意最后一個(gè)Employee的id來(lái)自map1而name來(lái)自map2.
原因是我們的merge函數(shù)的定義
(v1, v2) -> new Employee(v1.getId(), v2.getName())
4. Stream.concat()
Java8的Stream API 也為解決該問(wèn)題提供了較好的解決方案。
首先需要將兩個(gè)map合為一個(gè)Stream。
Stream combined = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream());
我們需要將entry sets作為參數(shù),然后利用Collectors.toMap():將結(jié)果放到新的map中。
Map<String, Employee> result = combined.collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
該方法可以實(shí)現(xiàn)map的合并,但是有重復(fù)key會(huì)報(bào)IllegalStateException異常。
為了解決這個(gè)問(wèn)題,我們需要加入lambda表達(dá)式merger作為第三個(gè)參數(shù)
(value1, value2) -> new Employee(value2.getId(), value1.getName())
當(dāng)檢測(cè)到有重復(fù)Key時(shí)就會(huì)用到該lambda表達(dá)式。
現(xiàn)在把上面代碼組合在一起:
Map<String, Employee> result = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (value1, value2) -> new Employee(value2.getId(), value1.getName())));
最終的結(jié)果
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
Henry=Employee{id=3, name='Henry'}
從結(jié)果可以看出重復(fù)的key “Henry”將合并為一個(gè)新的鍵值對(duì),id取自map2,name取自map1。
5. Stream.of()
通過(guò)Stream.of()方法不需要借助其他stream就可以實(shí)現(xiàn)map的合并。
Map<String, Employee> map3 = Stream.of(map1, map2) .flatMap(map -> map.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> new Employee(v1.getId(), v2.getName())));
首先將map1和map2的元素合并為同一個(gè)流,然后再轉(zhuǎn)成map。通過(guò)使用v1的id和v2的name來(lái)解決重復(fù)key的問(wèn)題。
map3的運(yùn)行打印結(jié)果如下:
6. Simple Streaming
我們還可以借助stream的管道操作來(lái)實(shí)現(xiàn)map合并。
Map<String, Employee> map3 = map2.entrySet() .stream() .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> new Employee(v1.getId(), v2.getName()), () -> new HashMap<>(map1)));
結(jié)果如下:
{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 的增強(qiáng)庫(kù)
Map<String, Employee> map3 = EntryStream.of(map1) .append(EntryStream.of(map2)) .toMap((e1, e2) -> e1);
注意 (e1, e2) -> e1 表達(dá)式來(lái)處理重復(fù)key的問(wèn)題,如果沒(méi)有該表達(dá)式依然會(huì)報(bào)IllegalStateException異常。
結(jié)果:
{George=Employee{id=2, name='George'},
John=Employee{id=8, name='John'},
Annie=Employee{id=22, name='Annie'},
Henry=Employee{id=1, name='Henry'}}
8 總結(jié)
本文使用了Map.merge(), Stream API, StreamEx 庫(kù)實(shí)現(xiàn)map的合并。
英文原文地址:https://www.baeldung.com/java-merge-maps
到此這篇關(guān)于詳解Java8合并兩個(gè)Map中元素的正確姿勢(shì)的文章就介紹到這了,更多相關(guān)Java8合并Map中元素內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java分頁(yè)查詢的幾種實(shí)現(xiàn)方法舉例
這篇文章主要給大家介紹了關(guān)于Java分頁(yè)查詢的幾種實(shí)現(xiàn)方法,分頁(yè)是系統(tǒng)中常用到的功能,只要涉及到查詢必定伴隨而來(lái)的就是分頁(yè),文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06logback整合rabbitmq實(shí)現(xiàn)消息記錄日志的配置
這篇文章主要介紹了logback整合rabbitmq實(shí)現(xiàn)消息記錄日志的配置,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-12-12Java微信二次開(kāi)發(fā)(三) Java微信各類型消息封裝
這篇文章主要為大家詳細(xì)介紹了Java微信二次開(kāi)發(fā)第三篇,Java微信各類型消息封裝,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Java多線程的實(shí)現(xiàn)方式比較(兩種方式比較)
Java多線程實(shí)現(xiàn)方式有兩種,第一種是繼承Thread類,第二種是實(shí)現(xiàn)Runnable接口,兩種有很多差異,下面跟著本文一起學(xué)習(xí)吧2015-11-11RestTemplate報(bào)錯(cuò)I/O?error?on?POST?request?for的解決辦法
這篇文章主要給大家介紹了關(guān)于RestTemplate報(bào)錯(cuò)I/O?error?on?POST?request?for的解決辦法,文中通過(guò)代碼實(shí)例將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08