详解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, value, (v1, v2) -> new Employee(v1.getId(),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) -> new Employee(v1.getId(), 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, value2) -> new Employee(value2.getId(), value1.getName())));

最终的结果

George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, 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,
 Map.Entry::getValue,
 (v1, v2) -> new Employee(v1.getId(), 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,
 Map.Entry::getValue,
 (v1, v2) -> new Employee(v1.getId(), 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, name='George'},
John=Employee{id=8, name='John'},
Annie=Employee{id=22, name='Annie'},
Henry=Employee{id=1, name='Henry'}}

8 总结

本文使用了Map.merge(), Stream API, StreamEx 库实现map的合并。

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

到此这篇关于详解Java8合并两个Map中元素的正确姿势的文章就介绍到这了,更多相关Java8合并Map中元素内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java导出excel时合并同一列中相同内容的行思路详解

    一.有时候导出Excel时需要按类别导出,一大类下好几个小类,小类下又有好几个小小类,就像下图: 要实现这个也不难, 思路如下:按照大类来循环,如上就是按照张江校区.徐汇校区.临港校区三个大类循环,然后再处理小类,因为本例小小类不涉及合并,所以只涉及处理小类,如果需要处理小小类,还需要在处理一下,具体实现原理同小类: 每次循环时记录下此次循环的房屋类型和上次循环的房屋类型,两者相同时,要合并的结束行++,否者,说明这个房屋类型已经循环完毕(前提是各类型都按顺序order by 了,保证相同类型相

  • java中两个byte数组实现合并的示例

    今天在于硬件进行交互的过程中,要到了了需要两个数组进行合并,然后对数组进行反转和加密操作,以下是两个byte数组合并的方法. /** * * @param data1 * @param data2 * @return data1 与 data2拼接的结果 */ public static byte[] addBytes(byte[] data1, byte[] data2) { byte[] data3 = new byte[data1.length + data2.length]; Syste

  • java实现合并单元格的同时并导出excel示例

    介绍 POI提供API给Java程序对Microsoft Office格式档案读和写的功能.POI可以操作的文档格式有excel,word,powerpoint等,POI进行跨行需要用到对象HSSFSheet对象,现在就当我们程序已经定义了一个HSSFSheet对象sheet. 跨第1行第1个到第2个单元格的操作为 sheet.addMergedRegion(new Region(0,(short)0,0,(short)1)); 跨第1行第1个到第2行第1个单元格的操作为 sheet.addMe

  • java实现合并2个文件中的内容到新文件中

    编写一个程序 将a.txt文件中的单词与b.txt文件中的单词交替合并到c.txt文件中 a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格进行分隔. 复制代码 代码如下: package javase.arithmetic; import com.google.common.base.Charsets; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.

  • java 两个数组合并的几种方法

    本文介绍了java 两个数组合并的几种方法,分享给大家,也给自己留个笔记 需求:两个字符串合并(如果想去重复,参考下一篇--数组去重复及记录重复个数) //方法一 Arrays类 String[] a = {"A","B","C"}; String[] b = {"D","E"}; // List<String> list = Arrays.asList(a); --OK // List<

  • Java 使用IO流实现大文件的分割与合并实例详解

    Java 使用IO流实现大文件的分割与合并 文件分割应该算一个比较实用的功能,举例子说明吧比如说:你有一个3G的文件要从一台电脑Copy到另一台电脑, 但是你的存储设备(比如SD卡)只有1G ,这个时候就可以把这个文件切割成3个1G的文件 ,分开复制, 最后把三个文件合并, 这样就解决问题了 :再比如说, 你有一个上百M的文件要上传到FTP ,但是这个FTP限制你单个文件不能超过10M 这时候也可以用文件分割的办法解决问题.既然分割了,那么在我们再次使用的时候就需要合并了,今天我们就通过Java

  • java实现合并图片的方法示例

    本文实例讲述了java实现合并图片的方法.分享给大家供大家参考,具体如下: package com.test; import java.io.File; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; public class ImageCombineTest { public static void main(String args[]) { try { // 读取第一张图片 File fileOne = n

  • java实现mp3合并的方法

    本文实例讲述了java实现mp3合并的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: package test; import java.io.*; import java.util.*; public class Test6 {     public static void main(String[] args) throws Exception     {         String s = "D:/out.mp3"; // 输出目录 & 文件名  

  • 详解Java合并数组的两种实现方式

    最近在写代码时遇到了需要合并两个数组的需求,突然发现以前没用过,于是研究了一下合并数组的方式,总结如下. 1.System.arraycopy()方法 (1) 解析 通过阅读JDK源码,我可以知道方法原型如下: public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 其中: src是源数组 srcPos是源数组复制的起始位置 dest是目标数组 destP

  • java字符串的合并

    答:import java.util.*; class test { public static void main(String[] args) { String str1="001,002,003,004,006",str2 = "001,002,005"; String str=""; TreeSet ts = new TreeSet(); StringTokenizer st = new StringTokenizer(str1,&quo

  • java实现大文件分割与合并的实例代码

    复制代码 代码如下: package com.test; import java.io.BufferedReader;  import java.io.BufferedWriter;  import java.io.FileNotFoundException;  import java.io.FileReader;  import java.io.FileWriter;  import java.io.IOException;  import java.util.Collections;  im

随机推荐