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

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

Java8 Collectors.toMap的坑的更多相关文章

  1. java8 list转Map报错Collectors.toMap :: results in &quot;Non-static method cannot be refernced from static context&quot;

    1.问题:java8 list转Map 报错Collectors.toMap :: results in "Non-static method cannot be refernced fro ...

  2. 使用Collectors.toMap遇到NullPointerException

    这个坑也是踩过好几次了,记录一笔. 当试图使用Collectors.toMap将一个stream收集为Map的时候,若构造map的valueMapper返回null时,则会报NullPointerEx ...

  3. Java8 list转map 坑

    Map<String , SonCargosForm> orderCargosMap = sonTemporaryForm.getOrderCargosList().stream() .c ...

  4. java 8 lamda Stream的Collectors.toMap 参数

    使用toMap()函数之后,返回的就是一个Map了,自然会需要key和value.toMap()的第一个参数就是用来生成key值的,第二个参数就是用来生成value值的.第三个参数用在key值冲突的情 ...

  5. Collectors.toMap不允许Null Value导致NPE

    背景 线上某任务出现报警,报错日志如下: java.lang.NullPointerException: null at java.util.HashMap.merge(HashMap.java:12 ...

  6. Java8 Period.between方法坑及注意事项

    在使用Java8 新特性中关于Period.between的方法时需注意该方法获取日期的区间问题. @Test public void test1(){ LocalDate from = LocalD ...

  7. Java8 Collectors类的静态工厂方法

    预定义收集器的功能,就是那些可以从Collectors类提供的工厂方法(例如grouping By)创建的收集器. 它们主要提供了三大功能: •将流元素归约和汇总为一个值 •元素分组 •元素分区 •c ...

  8. 这些Java8官方挖过的坑,你踩过几个?

    导读:系统启动异常日志竟然被JDK吞噬无法定位?同样的加密方法,竟然出现部分数据解密失败?往List里面添加数据竟然提示不支持?日期明明间隔1年却输出1天,难不成这是天上人间?1582年神秘消失的10 ...

  9. java8 array、list操作 汇【3】)(-Java8新特性之Collectors 详解

    //编写一个定制的收集器 public static class MultisetCollector<T> implements Collector<T, Multiset<T ...

随机推荐

  1. C4.5(决策树)

    C4.5是一系列用在机器学习和数据挖掘的分类问题中的算法.它的目标是监督学习:给定一个数据集,其中的每一个元组都能用一组属性值来描述,每一个元组属于一个互斥的类别中的某一类.C4.5的目标是通过学习, ...

  2. mybaits in

    mybatis中的in: <select id="getByInventoryIds" resultMap="beanMap"> SELECT * ...

  3. 多条查询sql语句返回多表数据集

    + + "';SELECT ProductID,ProductTitle,ProductName,SalePrice,ListingPrice,MainPicture,SaledItemCo ...

  4. Scrapy运行报错解决方案

    最近在学习Scrapy框架,用博客记录一下遇到的错误的解决方案 时间: 2016-9-20 错误:ImportError: No module named items 原因:spiders下的.py文 ...

  5. VC中如何获取当前时间(精度达到毫秒级)

    标 题: VC中如何获取当前时间(精度达到毫秒级)作 者: 0xFFFFCCCC时 间: 2013-06-24链 接: http://www.cnblogs.com/Y4ng/p/Millisecon ...

  6. 数学之路-python计算实战(15)-机器视觉-滤波去噪(归一化块滤波)

    # -*- coding: utf-8 -*- #code:myhaspl@myhaspl.com #归一化块滤波 import cv2 import numpy as np fn="tes ...

  7. C# 百分比的获取

    这里介绍 C# 百分比转换有2种方式 例: double a=50; double b=100; a/b.ToString("0.00%"); 或 a/b.ToString(&qu ...

  8. 转 Java输入输出流详解(非常详尽)

    转  http://blog.csdn.net/zsw12013/article/details/6534619 通过数据流.序列化和文件系统提供系统输入和输出. Java把这些不同来源和目标的数据都 ...

  9. [20180408]那些函数索引适合字段的查询.txt

    [20180408]那些函数索引适合字段的查询.txt --//一般不主张建立函数索引,往往是开发的无知,使用trunc等函数,实际上一些函数也可以用于字段的查询.--//以前零碎的写过一些,放假看了 ...

  10. BZOJ4808马——二分图最大独立集

    题目描述 众所周知,马后炮是中国象棋中很厉害的一招必杀技."马走日字".本来,如果在要去的方向有别的棋子挡住(俗 称"蹩马腿"),则不允许走过去.为了简化问题, ...