java8的lambda中的map相关操作

2023-11-08

0 入门详解篇

 史上最简单入门:java8的lambda中的map相关操作:基础及注意事项图文详解

2   java8的lambda中collect接口案例及原理详解,官方文档解读

3   java8:封装lambda泛型工具类之list转为map

4   java8的lambda中的map操作:合并两个map


1 以下是正文

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

原文链接:https://blog.csdn.net/w605283073/article/details/82987157

1. 介绍

本入门教程将介绍Java8中如何合并两个map。如果想学习入门教程点击开篇0入门篇lambda表达式:list转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://github.com/eugenp/tutorials/tree/master/core-java-collections

二:Java8使List转为Map

https://blog.csdn.net/hanerer1314/article/details/78826068

import com.yang.test.User;
 
import javax.jws.soap.SOAPBinding;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
 
public class Main {
 
    public static void main(String[] args) {
 
        List<User> userlist = new ArrayList<>();
        for (int i = 0; i <10; i++) {
 
            userlist.add(new User("张三"+i,i));
        }
        System.out.println(getAllages(userlist).size());
 
        System.out.println(getUser2Map(userlist));
 
        System.out.println(getUser2MapUser(userlist));
 
        System.out.println(getUser2MapUser2(userlist));
 
          System.out.println(getUser2MapUser3(userlist));
 
    }
 
    public static List<Integer> getAllages(List<User>userlist){
        return  userlist.stream().map(user -> user.getAge()).collect(Collectors.toList());
    }
 
    public static Map<Integer,String> getUser2Map(List<User>userlist){
 
        return userlist.stream().collect(Collectors.toMap(User::getAge,User::getName));
    }
 
    public static Map<Integer,User> getUser2MapUser(List<User>userlist){
 
        return userlist.stream().collect(Collectors.toMap(User::getAge,User-> User));
    }
 
    /**
     * 比较优雅的写法是这样的
     * @param userlist
     * @return
     */
    public static Map<Integer,User> getUser2MapUser2(List<User>userlist){
 
        return userlist.stream().collect(Collectors.toMap(User::getAge, Function.identity()));
    }
 
    /**
     * 重复key的情况下 简单的使用后者覆盖前者的
     */
    public static Map<Integer,User> getUser2MapUser3(List<User>userlist){
 
        return userlist.stream().collect(Collectors.toMap(User::getAge, Function.identity(),(key1,key2)->key2));
    }
 
    /**
     *指定map的具体实现
     * @param userlist
     * @return
     */
    public static Map<Integer,User> getUser2MapUser4(List<User>userlist){
 
        return userlist.stream().collect(Collectors.toMap(User::getAge, Function.identity(),(key1,key2)->key2, LinkedHashMap::new));
    }
}

Function.identity()用的默认的也可以是x->x 即value是user

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java8的lambda中的map相关操作 的相关文章

随机推荐

  • taro请求工具封装

    taro框架是一个跨端兼容的开发框架 自带了请求相关的API 虽然灵活 但是封装程度并不高 会导致比较多的代码冗余 因此封装了一个请求相关的工具 思路如下 1 请求和响应需要拦截器 针对不同的情况做不同的处理 2 开发中分为开发 测试 生成
  • Ajax跨域问题

    什么是跨域问题 跨域问题来源于JavaScript的 同源策略 即只有 协议 主机名 端口号 如存在 相同 则允许相互访问 也就是说JavaScript只能访问和操作自己域下的资源 不能访问和操作其他域下的资源 跨域问题是针对JS和ajax
  • ELK多个日志文件创建多个项目索引

    一 背景 我的elk架构是filebeat redis logstash elasticsearch kibana 我的想法是 我一台服务器多个程序有多个日志文件 在kibana里面想创建不通项目索引 指定不同日志文件 二 问题及解决思路
  • python环境安装和激活

    开始学习python了 环境的安装对与新手来说就变的比较麻烦 这里就会为大家介绍pycharm和python解释器的安装 python解释器的安装 这里介绍windows安装方式 mac安装方法类似 python解释器下载地址 https
  • STL源码阅读-traits与迭代器

    迭代器模式 提供一种方法 使之能够依序访问容器的各个元素 而又无需暴露容器的内部表述方式 STL设计的中心思想在于将数据容器和算法分离开 容器和算法分开设计 迭代器则是两者之间的胶着剂 一般迭代器的设计与容器细节相关 所以一般交给容器的设计
  • 《Effective C++》 全书内容提炼总结

    个人博客地址 https cxx001 gitee io 本文阅读说明 孔子云 取乎其上 得乎其中 取乎其中 得乎其下 取乎其下 则无所得矣 对于读书求知而言 这句古训教我们去读好书 最好是好书中的上品 经典书 Effective C 就是
  • 通过CSS实现 文字渐变色 的两种方式

    主要实现文字渐变色有两种方式 background 属性 mask 属性 1 background 属性 效果图如下 span 这 span
  • 一个30岁光棍的内心独白

    人已三十开外 至今独赏天籁 好想有个太太 为我洗衣做菜 现实却很无奈 让我继续等待 也因寂寞难耐 谈过几次恋爱 谁知屡战屡败 轻轻松松被踹 其实我也奇怪 为啥总遭淘汰 历尽打击伤害 总算知道大概 嫌我不讲穿戴 嫌我长的不帅 熊猫长的不帅 却
  • 代价函数(Cost Function)

    基本概念 代价函数也被称作平方误差函数 有时也被称为平方误差代价函数 我们之所以要求出误差的平方和 是因为误差平方代价函数 对于大多数问题 特别是回归问题 都是一个合理的选择 还有其他的代价函数也能很好地发挥作用 但是平方误差代价函数可能是
  • 腾讯云服务器开通root用户

    01 开通root用户 sudo passwd root 输入 root 的密码 按Enter 重复输入 root 的密码 按Enter 返回如下信息 即表示 root 密码设置成功 passwd password updated succ
  • 信号完整性之差分对

    差分传输 差分互连方式中 使用两条传输线来传输信号 差分驱动器有两个输出端 这两个输出端同时输出信号 理想情况下两个信号边沿对齐 但是翻转方向相反 如下图所示 两个信号沿着各自的传输线传输 到达接收器时 接收器对两个信号进行差分检测 从两个
  • CodeForces 920C Swap Adjacent Elements

    题目大意 题目链接 给定一个序列 这个序列可以理解为一个1 n的全排列 再给出一个01串 1表示可以将索引i和i 1进行交换 且交换可以发生任意次 0表示不可以 问最后能不能将序列升序排列 题解 几乎 秒杀 因为简单 判断每个索引处的数能不
  • 数据库——关系数据库规范化习题

    对以下的关系模式 分别写出 1 码 主属性 非主属性 2 函数依赖 3 属于第几范式 为什么 4 有什么问题 5 如何分解 分解后能否达到几范式 原问题是否解决 ps 函数依赖的方法 1 先找出码 再写出码函数依赖 码 其他属性 2 再写出
  • 电脑宝马,大量宝马车电脑通病故障检修方法

    车型 宝马X5 X6 N55发动机 故障现象 报电子节气门故障 解决方法 检测那个芯片更换即可 车型 宝马E60 E66 E65 故障现象 天使眼不亮 解决方法 刷此程序即可 故障现象 手刹不好用 报内部故障 解决方法 将此处焊接即可 车型
  • 【git】2、gitlab CICD 模型部署自动化

    文章目录 一 GitLab 二 GitLab CI CD 2 1 gitlab ci yml 2 1 1 基础概念 2 1 2 创建 yml 文件 2 1 3 yml 文件中的关键字 2 2 GitLab Runner 一 GitLab G
  • android configChanges属性

    给对应的Activity配置 android configChanges orientation screenSize 横竖屏切换就不会重新创建Activity 学习到这个属性 是因为一个bug activity上有tablayout vi
  • 界面开发(二)--- NativeWindow

    NativeWindow是 net Framework提供的一个底层的类 微软官方的解释为 NativeWindow Provides a low level encapsulation of a window handle and a w
  • 虚拟机redhat9开机不能进入图形界面解决办法

    在启动时无法进入图形界面 出现错误提示 Markers probed from config file default setting from command line notice II informational WW warning
  • c#面试3(选择题)

    46 下列关于 C 中索引器理解正确的是 c A 索引器的参数必须是两个或两个以上 B 索引器的参数类型必须是整数型 C 索引器没有名字 D 以上皆非 47 以下关于 ref 和 out 的描述哪些项是正确的 多选 ACD A 使用 ref
  • java8的lambda中的map相关操作

    0 入门详解篇 1 史上最简单入门 java8的lambda中的map相关操作 基础及注意事项图文详解 2 java8的lambda中collect接口案例及原理详解 官方文档解读 3 java8 封装lambda泛型工具类之list转为m