成都武侯区网站建设,网站开发工程师学什么,个人网站托管,ppt怎么做 pc下载网站Java 8中的stream在项目开发中被同学们用的风生水起#xff0c;当然大家也踩了不少坑。下面我就来说说Collections.toMap在项目使用中踩的坑#xff0c;避免大家重复被坑。 一.介绍Collectors.toMap
Collectors.toMap 是 Java 8 中的一个收集器#xff0c;它可以将流中的元… 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) {ListBenefitModel benefitModelList new ArrayList();benefitModelList.add(new BenefitModel(123, 积分权益));benefitModelList.add(new BenefitModel(123, 现金权益));MapString, 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) {ListBenefitModel benefitModelList new ArrayList();benefitModelList.add(new BenefitModel(123, 积分权益));benefitModelList.add(new BenefitModel(123, 现金权益));MapString, 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) {ListBenefitModel benefitModelList new ArrayList();benefitModelList.add(new BenefitModel(123, 积分权益));benefitModelList.add(new BenefitModel(124, null));MapString, 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。 MapString, String map2 benefitModelList.stream().filter(m - m.getBenefitName() ! null).collect(Collectors.toMap(BenefitModel::getBenefitId, BenefitModel::getBenefitName));
方案2查资料评价度最好的方案如下。其实跟你方案1中思路-手动foreach一毛一样。 MapString, 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