Collectors.toMap报错:空指针 key重复

Java 8中的stream在项目开发中被同学们用的风生水起,当然大家也踩了不少坑。下面我就来说说Collections.toMap在项目使用中踩的坑,避免大家重复被坑。


一.介绍Collectors.toMap

Collectors.toMap 是 Java 8 中的一个收集器,它可以将流中的元素转换为 Map 对象,其中每个元素的 key 由指定的函数生成。

当我们使用 Collectors.toMap 方法时,可能会遇到重复的 key 问题,这是因为我们在将元素转化为 Map 对象时,如果两个元素具有相同的 key,则会发生冲突,抛出异常。

还可能会遇到value为null的问题,这是因为我们在将元素转化为 Map 对象时,toMap最终是调用了Map.merge方法,merge方法不允许value为null 导致的异常抛出。

二.问题复现与分析以及解决方案

1、Collectors.toMap的key重复问题

问题复现:
    public static void main(String[] args) {List<BenefitModel> benefitModelList = new ArrayList<>();benefitModelList.add(new BenefitModel("123", "积分权益"));benefitModelList.add(new BenefitModel("123", "现金权益"));Map<String, String> benefitMap = benefitModelList.stream().collect(Collectors.toMap(BenefitModel::getBenefitId, BenefitModel::getBenefitName));System.out.println(JSON.toJSONString(benefitMap));}
运行结果:

原因分析:

查看Collectors.toMap源码如下,

toMap最终是调用了Map.merge方法,传入的mergeFunction是throwingMerger直接抛出异常,日志信息使用的是第一个参数u。传入的mapSupplier是HashMap对象(HashMap::new)。所以最终会调用到HashMap.merge。

而在HashMap.merge中,对于mergeFunction的应用如下:

在HashMap.merge的语义中,mergeFunction用于合并value,比如对于key的计数,可以使用map.merge(key, 1, Integer::sum)。若不存在则置1,存在则+1。这里的入参是oldValue和newValue。

所以最终传递给throwingMerger的两个参数就不是k-v了。所以报错的所谓Duplicate key其实是oldValue。

解决方案:
  • 保证toMap的key不重复
  • 调用重载方法,主动指定当key重复时,需要做的合并操作(合并规则可以根据业务需要,自定义)

于是上面重复key的代码优化后为:(合并规则:重复key出现时,取后面的,前面的丢弃)

    public static void main(String[] args) {List<BenefitModel> benefitModelList = new ArrayList<>();benefitModelList.add(new BenefitModel("123", "积分权益"));benefitModelList.add(new BenefitModel("123", "现金权益"));Map<String, String> map = benefitModelList.stream().collect(Collectors.toMap(BenefitModel::getBenefitId, BenefitModel::getBenefitName,(k1, k2) -> k2));System.out.println(JSON.toJSONString(map));}
高版本JDK的修复措施:

重复key这个问题在后续版本中得到修复,比如在JDK 11中的处理。

2、Collectors.toMap的value值为null问题

问题复现:
    public static void main(String[] args) {List<BenefitModel> benefitModelList = new ArrayList<>();benefitModelList.add(new BenefitModel("123", "积分权益"));benefitModelList.add(new BenefitModel("124", null));Map<String, String> benefitMap = benefitModelList.stream().collect(Collectors.toMap(BenefitModel::getBenefitId, BenefitModel::getBenefitName));System.out.println(JSON.toJSONString(benefitMap));}
运行结果:

原因分析:

有问题,看源码,查看Collectors.toMap源码如下,

toMap最终是调用了Map.merge方法,而在HashMap.merge中,对于value的应用如下:

在HashMap.merge的语义中,value使用前需要进行判空处理,null直接抛出异常NullPointerException。

解决方案:

方案1:先把value为null的数据过滤掉,再用Collectors.toMap。

        Map<String, String> map2 = benefitModelList.stream().filter(m -> m.getBenefitName() != null).collect(Collectors.toMap(BenefitModel::getBenefitId, BenefitModel::getBenefitName));

方案2:查资料评价度最好的方案如下。其实跟你方案1中思路-手动foreach一毛一样。

        Map<String, String> map2 = benefitModelList.stream().collect(HashMap::new, (m, v) -> m.put(v.getBenefitId(), v.getBenefitName()),HashMap::putAll);
高版本JDK的修复措施:

Collectors.toMap使用时,value值为null,这个问题在Java 11中仍然存在。可能value为null,这种数据很少见,促使解决过程比较缓慢。

三、Collectors.toMap使用总结

综上所以,在使用Collectors.toMap时需要记住几点:

1、key不能有重复,否则会报错IllegalStateException: Duplicate key,因为Map的key不能重复。

2、value不能为空,否则报错NullPointerException。

看完了本文,你可以去搜搜你的项目代码中使用Collectors.toMap的地方,有没有可能踩上面的坑。不要说你的业务数据不会出现重复key的数据,不会出现value值null的情况,上百万的业务数据,什么情况都会有的。

参考资料:java - Ignore duplicates when producing map using streams - Stack Overflow

java - NullPointerException in Collectors.toMap with null entry values - Stack Overflow

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/126317.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# OpenCvSharp DNN 部署L2CS-Net人脸朝向估计

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_DNN_Demo …

hadoop hdfs的API调用,在mall商城代码中添加api的调用

在网上下载了现成的商城代码的源码 本次旨在熟悉hdfs的api调用&#xff0c;不关注前后端代码的编写&#xff0c;所以直接下载现成的代码&#xff0c;代码下载地址。我下载的是前后端在一起的代码&#xff0c;这样测试起来方便 GitHub - newbee-ltd/newbee-mall: &#x1f525; …

Seata入门系列【18】Seata集成Mybatis-Plus多数据源

1 前言 在使用单个服务&#xff0c;多数据源时&#xff0c;也存在分布式事务问题。 当单体系统需要访问多个数据库&#xff08;实例&#xff09;时就会产生分布式事务。 比如&#xff1a;用户信 息和订单信息分别在两个MySQL实例存储&#xff0c;用户管理系统删除用户信息&am…

驱动开发11-2 编写SPI驱动程序-点亮数码管

驱动程序 #include <linux/init.h> #include <linux/module.h> #include <linux/spi/spi.h>int m74hc595_probe(struct spi_device *spi) {printk("%s:%d\n",__FILE__,__LINE__);char buf[]{0XF,0X6D};spi_write(spi,buf,sizeof(buf));return 0; …

【SpringMVC篇】5种类型参数传递json数据传参

&#x1f38a;专栏【SpringMVC】 &#x1f354;喜欢的诗句&#xff1a;天行健&#xff0c;君子以自强不息。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f33a;普通参数&#x1f33a;POJO参数&#x1f33a;嵌套…

nacos 常见问题整理包含容器环境

文章目录 0. nacos客户端日志文件位置最常见的问题1. 容器环境端口开放不够导致的问题原理解析 2.服务端启用了鉴权客户端常见错误信息如下服务端报错信息如下 其他一些问题0. nacos高版本服务端是否支持旧的客户端&#xff1f;1. Error code:503,msg:server is DOWN now, plea…

【UE5】如何在UE5.1中创建级联粒子系统

1. 可以先新建一个actor蓝图&#xff0c;然后在该蓝图中添加一个“Cascade Particle System Component” 2. 在右侧的细节面板中&#xff0c;点击“模板”一项中的下拉框&#xff0c;然后点击“Cascade粒子系统&#xff08;旧版&#xff09;” 然后就可以选择在哪个路径下创建级…

前端Vue框架系列—— 学习笔记总结Day04

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

Java NIO为何导致堆外内存OOM了?

Java NIO为何导致堆外内存OOM了&#xff1f; 描述 某天报警&#xff1a;某台机器部署的一个服务突然无法访问。谨记第一反应登录机器查看日志&#xff0c;因为服务挂掉&#xff0c;很可能因OOM。这个时候在机器的日志中发现了如下的一些信息&#xff1a; nio handle failed j…

Leetcode—485.最大连续1的个数【中等】明天修改

2023每日刷题&#xff08;十五&#xff09; Leetcode—2.两数相加 迭代法实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l…

Python使用got库如何写一个爬虫代码?

got库是一个Python的HTTP库&#xff0c;可以用于爬取网页数据。它提供了简单易用的API&#xff0c;支持异步请求和爬虫IP设置等功能。使用got库进行爬虫开发&#xff0c;可以快速地获取所需数据。下面是使用got库进行爬虫的基本步骤&#xff1a; 1、安装got库&#xff1a;可以使…

ruoyi框架前端修改message消失时间

修改教程 打开modal.js文件&#xff0c;找到Message.success&#xff0c;然后把参数设置进去就行。单位是10001秒。 // 可以设置的参数如下export interface ElMessageOptions {/** Message text */message: string | VNode/** Message type */type?: MessageType/** Custom …

4.5 Object类

思维导图&#xff1a; 4.5 Object类笔记总结 1. 定义和重要性 Java提供的Object类是所有Java类的根类。直接或间接&#xff0c;所有的Java类都继承自Object类。它被称为超类。 2. 默认行为 当创建一个新的类且没有显式地使用extends关键字指定一个父类时&#xff0c;该类默认…

Microsoft Edge不能工作了,可能原因不少,那么如何修复呢

Microsoft Edge打不开或不能加载网页是用户在Windows 10、Android、Mac和iOS设备上的网络浏览器上遇到的许多错误之一。其他Microsoft Edge问题可能包括浏览器窗口和选项卡冻结、网站崩溃、互联网连接错误消息以及丢失Microsoft Edge书签、收藏夹、密码和收藏。 Microsoft Edg…

金蝶云星空自定义校验器和使用

文章目录 金蝶云星空自定义校验器和使用 金蝶云星空自定义校验器和使用 1、创建类&#xff0c;并继承抽象接口 using Kingdee.BOS.Core; using Kingdee.BOS.Core.Validation; using System;namespace mm.K3.SCM.App.Service.PlugIn.SC.Validator {public class AfterOrderChe…

跨境电商大作战:2023黑色星期五准备指南

黑色星期五&#xff0c;作为全球购物狂欢的象征&#xff0c;已经成为了电商业务的一年一度的重要节点。尤其对于跨境电商来说&#xff0c;这一天意味着巨大的商机和挑战。为了在这个竞争激烈的时刻脱颖而出&#xff0c;跨境电商必须做好充分的准备。Nox聚星在这里给大家分享几个…

最新ai系统ChatGPT程序源码+详细搭建教程+以图生图+Dall-E2绘画+支持GPT4+Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

Q-CTRL首次在量子市场获得ISO 27001国际标准认证

​&#xff08;图片来源&#xff1a;网络&#xff09; 国际公认的ISO 27001标准概述了信息安全管理系统&#xff08;ISMS&#xff09;的实施&#xff0c;并表现了管理风险的能力&#xff0c;包括与客户数据安全相关的风险。总部位于悉尼的Q-CTRL是第一家获得ISO 27001认证的独…

学生成绩这样分发

作为一名老师&#xff0c;经常被问到这样的问题&#xff1a;“老师&#xff0c;我的成绩什么时候发&#xff1f;”、“老师&#xff0c;我的成绩出来了吗&#xff1f;”等等。倍感烦恼&#xff0c;需要花费时间来回答这些问题&#xff0c;而且有时候学生还会因为成绩不佳而抱怨…

C++对象的内存分布和虚函数表

Linux C/C 开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全) c中一个类中无非有四种成员&#xff1a;静态数据成员和非静态数据成员&#xff0c;静态函数和非静态函数。 1.非静态数据成员被放在每一个对象体内作为对象专有的数据成员。 2.静态数据成员被提取出来…