按照常规思维,往一个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 "Non-static method cannot be refernced from static context"

    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. 利用powershell进行windows日志分析

    0x00 前言 Windows 中提供了 2 个分析事件日志的 PowerShell cmdlet:一个是Get-WinEvent,超级强大,但使用起来比较麻烦:另一个是Get-EventLog,使得 ...

  2. mac 常用的终端命令

    OSX 的文件系统 OSX 采用的Unix文件系统,所有文件都挂在跟目录 / 下面,所以不在要有Windows 下的盘符概念. 你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做 US ...

  3. C语言中打印返回值

    demo: ----return :返回值------------------ int mosquitto_username_pw_set(struct mosquitto *mosq, const ...

  4. C语言中的正负数及其输出

    在数学中,数字有正负之分.在C语言中也是一样,short.int.long 都可以带上正负号,例如: //负数 ; short a2 = -0x2dc9; //十六进制 //正数 ; ; //八进制 ...

  5. 教你在windows下安装使用配置vim+gcc[转]

    转自http://blog.163.com/lixiangqiu_9202/blog/static/535750372012461190722/ 一直在使用linux,但有时也会去虚拟机里的winxp ...

  6. PrintWriter 和 Scanner 类的组合使用

    // 示例程序:将一个Employee记录数组存储成一个文本文件,其中每个记录都保存在单独的一行中, // 而实例的域彼此之间使用分隔符分离开. // 众所周知: // 以二进制格式写出数据,需要使用 ...

  7. Android井字游戏(二)游戏界面

    图片与代码可见书配套官网下载 1 棋盘 1.1  先将游戏界面所需的图片放于“drawable-xxhdpi”文件夹中,后缀xxhdpi表示超高密度. 然后将图片封装到drawable中一个名为til ...

  8. open-falcon之judge

    功能 judge 模块主要从transfer中接收数据,并从HBS中获取报警策略,然后进行阈值报警判断 从HBS获取报警策略 接收transfer 上报的数据,并存储最新几个点 判断阈值,产生报警事件 ...

  9. windows下php使用protobuf

    1.下载protobufc https://github.com/google/protobuf/releases/download/v3.5.0/protoc-3.5.0-win32.zip解压后放 ...

  10. java.lang.NoClassDefFoundError: Could not initialize class xxx 原因

    一.问题及原因 程序里有个工具类,主要是调用它的静态方法来发送mq. 调用场景如下: 结果这两天报了个错: java.lang.NoClassDefFoundError: Could not init ...