Java8 Collectors.toMap的坑

作者:欠扁的小篮子 时间:2023-06-24 14:47:48 

按照常规思维,往一个map里put一个已经存在的key,会把原有的key对应的value值覆盖,然而通过一次线上问题,发现Java8中的Collectors.toMap反其道而行之,它默认给抛异常,抛异常...

线上业务代码出现Duplicate Key的异常,影响了业务逻辑,查看抛出异常部分的代码,类似以下写法:


Map<Integer, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName));

然后list里面有id相同的对象,结果转map的时候居然直接抛异常了。。查源码发现toMap方法默认使用了个throwingMerger


public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
               Function<? super T, ? extends U> valueMapper) {
 return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}

private static <T> BinaryOperator<T> throwingMerger() {
 return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}

那么这个throwingMerger是哪里用的呢?


public static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
             Function<? super T, ? extends U> valueMapper,
             BinaryOperator<U> mergeFunction,
             Supplier<M> mapSupplier) {
 BiConsumer<M, T> accumulator
     = (map, element) -> map.merge(keyMapper.apply(element),
                    valueMapper.apply(element), mergeFunction);
 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}

这里传进去的是HashMap,所以最终走的是HashMap的merge方法。merge方法里面有这么一段代码:


if (old != null) {
 V v;
 if (old.value != null)
   v = remappingFunction.apply(old.value, value);
 else
   v = value;
 if (v != null) {
   old.value = v;
   afterNodeAccess(old);
 }
 else
   removeNode(hash, key, null, false, true);
 return v;
}

相信只看变量名就能知道这段代码啥意思了。。如果要put的key已存在,那么就调用传进来的方法。而throwingMerger的做法就是抛了个异常。所以到这里就可以知道写的代码为什么呲了。。

如果不想抛异常的话,自己传进去一个方法即可,上述代码可以改成:


Map<Integer, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName,(oldValue, newValue) -> newValue));

这样就做到了使用新的value替换原有value。

写代码调方法时,多看源码实现,注意踩坑!

来源:https://blog.csdn.net/u013805360/article/details/82686009

标签:Java8,Collectors.toMap
0
投稿

猜你喜欢

  • Maven插件的安装及使用

    2022-04-05 04:38:30
  • Java Document生成和解析XML操作

    2021-11-10 13:17:46
  • java文字转语音播报功能的实现方法

    2022-05-08 18:44:41
  • SpringCloud之熔断器Hystrix的实现

    2021-09-21 01:39:26
  • Springboot+AOP实现返回数据提示语国际化的示例代码

    2021-08-18 19:49:12
  • CDMA 猫用AT命令发中文短信(C#)

    2021-07-22 08:19:46
  • Spring 4.0新功能:@Conditional注解详细介绍

    2022-01-19 06:37:35
  • mybatis快速入门学习教程新手注意问题小结

    2023-08-23 18:52:38
  • Java synchronized重量级锁实现过程浅析

    2023-10-25 14:10:17
  • volatile与happens-before的关系与内存一致性错误

    2021-12-13 20:25:37
  • Springboot实现Shiro整合JWT的示例代码

    2022-01-30 02:58:32
  • C# protobuf自动更新cs文件

    2021-10-08 10:16:28
  • unity实现翻页效果

    2022-09-01 17:10:15
  • C# 通过NI-VISA操作Tektronix TBS 2000B系列示波器的实现步骤

    2023-11-02 01:44:38
  • C#中分部类和分部方法的应用

    2022-08-16 06:49:05
  • c#通用登录模块分享

    2023-07-21 15:54:31
  • Mybatis配置之typeAlias标签的用法

    2023-11-27 20:18:20
  • SpringBoot结合Neo4j自定义cypherSql的方法

    2022-05-18 00:41:07
  • Java中关键字synchronized的使用方法详解

    2022-04-14 06:18:54
  • Android Activity的启动过程源码解析

    2023-12-25 11:16:00
  • asp之家 软件编程 m.aspxhome.com