gpt4 book ai didi

Java8 Collectors.toMap的坑

转载 作者:qq735679552 更新时间:2022-09-29 22:32:09 27 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Java8 Collectors.toMap的坑由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
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是哪里用的呢?

?
1
2
3
4
5
6
7
8
9
10
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方法里面有这么一段代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的做法就是抛了个异常。所以到这里就可以知道写的代码为什么呲了。.

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

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

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

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

到此这篇关于Java8 Collectors.toMap的坑的文章就介绍到这了,更多相关Java8 Collectors.toMap内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。

原文链接:https://blog.csdn.net/u013805360/article/details/82686009 。

最后此篇关于Java8 Collectors.toMap的坑的文章就讲到这里了,如果你想了解更多关于Java8 Collectors.toMap的坑的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com