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