按照常规思维,往一个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。

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

最新文章

  1. 如何进行安全测试-XSS篇
  2. MySQL学习笔记——安装及配置环境
  3. call方法和new对象的关系
  4. POJ1743 Musical Theme
  5. 使用matplotlib绘制带图例的图表
  6. .Net 代码安全保护产品DNGuard HVM使用
  7. 你被adblock坑过吗?
  8. hdu3999The order of a Tree (二叉平衡树(AVL))
  9. java 操作FTP
  10. 食物链-HZUN寒假集训
  11. jmeter学习记录--08--第三方测试组件
  12. spring-boot(五) RabbitMQ详解 定时任务
  13. LOJ#2245 魔法森林
  14. 主线程——main线程
  15. MarkDown常用格式
  16. [蓝桥杯]ALGO-79.算法训练_删除数组零元素
  17. Javac常量池的解读
  18. MongoDb GridFS的使用
  19. mysql++ result
  20. Nine-patch

热门文章

  1. Java Cookie工具类,Java CookieUtils 工具类,Java如何增加Cookie
  2. Hashtable的应用
  3. linux制做RPM包
  4. linux下删除大量小文件
  5. 【存储过程】用SQL语句获得一个存储过程返回的表
  6. 【贪心】PAT 1033. To Fill or Not to Fill (25)
  7. shell 数值计算
  8. 关于windows下基于php7.0.2下编写的第一个扩展
  9. java(4) 异常
  10. LeetCode 19 Remove Nth Node From End of List (移除距离尾节点为n的节点)