详解Java8合并两个Map中元素的正确姿势

 更新时间:2020年09月02日 10:19:55   作者:明明如月学长  
这篇文章主要介绍了详解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中元素内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java @Value(

    Java @Value("${xxx}")取properties时中文乱码的解决

    这篇文章主要介绍了Java @Value("${xxx}")取properties时中文乱码的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Spring Boot提高开发效率必备工具lombok使用

    Spring Boot提高开发效率必备工具lombok使用

    这篇文章主要为大家介绍了Spring Boot提高开发效率的必备工具lombok使用方法示例及步骤说明,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-03-03
  • SpringBoot下Mybatis的缓存的实现步骤

    SpringBoot下Mybatis的缓存的实现步骤

    这篇文章主要介绍了SpringBoot下Mybatis的缓存的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • Spring Security角色继承分析

    Spring Security角色继承分析

    这篇文章主要介绍了Spring Security角色继承分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java实现贪吃蛇游戏

    Java实现贪吃蛇游戏

    这篇文章主要为大家详细介绍了Java实现贪吃蛇游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • Jmeter安装及配置教程详解

    Jmeter安装及配置教程详解

    很多朋友私信小编Jmeter安装及配置教程能出一期教程吗?正巧赶上疫情,不是太忙,下面小编把Jmeter安装及配置教程分享到脚本之家平台,感兴趣的朋友跟随小编一起看看吧
    2021-12-12
  • kotlin和Java的相互调用示例详解

    kotlin和Java的相互调用示例详解

    Kotlin 的设计过程中就考虑到了与 Java 的互操作性。在 Kotlin 中可以直接调用既有的 Java 代码, 反过来在 Java 中也可以很流畅地使用 Kotlin 代码,下面这篇文章主要给大家介绍了关于kotlin和Java的相互调用的相关资料,需要的朋友可以参考下。
    2018-02-02
  • 解析Java和IDEA中的文件打包问题

    解析Java和IDEA中的文件打包问题

    这篇文章主要介绍了Java和IDEA中的文件打包问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • java基础-数组扩容详解

    java基础-数组扩容详解

    这篇文章主要介绍了Java数组扩容实现方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-08-08
  • Java多线程之如何确定线程数的方法

    Java多线程之如何确定线程数的方法

    创建线程和销毁线程都是比较耗时的操作,如果每个任务都创建一个线程去处理,这样线程会越来越多,那么应该如何确定线程的数量,本文就详细的介绍一下,感兴趣的可以了解一下
    2022-03-03

最新评论