Java8 Collectors.toMap的坑

 更新时间:2021年03月18日 10:21:49   作者:欠扁的小篮子  
这篇文章主要介绍了Java8 Collectors.toMap的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

按照常规思维,往一个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的坑的文章就介绍到这了,更多相关Java8 Collectors.toMap内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解SpringBoot 发布ApplicationEventPublisher和监听ApplicationEvent事件

    详解SpringBoot 发布ApplicationEventPublisher和监听ApplicationEvent事

    这篇文章主要介绍了详解SpringBoot 发布ApplicationEventPublisher和监听ApplicationEvent事件,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-06-06
  • Java IO流对象的序列化和反序列化实例详解

    Java IO流对象的序列化和反序列化实例详解

    这篇文章主要介绍了Java IO流对象的序列化和反序列化实例详解的相关资料,需要的朋友可以参考下
    2017-05-05
  • java中aop实现接口访问频率限制

    java中aop实现接口访问频率限制

    本文主要介绍了java中aop实现接口访问频率限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • 解决mybatis case when 报错的问题

    解决mybatis case when 报错的问题

    这篇文章主要介绍了解决mybatis case when 报错的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • WIN7系统JavaEE(java)环境配置教程(一)

    WIN7系统JavaEE(java)环境配置教程(一)

    这篇文章主要介绍了WIN7系统JavaEE(java+tomcat7+Eclipse)环境配置教程,本文重点在于java配置,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Java初始化块及执行过程解析

    Java初始化块及执行过程解析

    这篇文章主要介绍了Java初始化块及执行过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Java中Properties的使用详解

    Java中Properties的使用详解

    这篇文章主要介绍了Java中Properties的使用详解的相关资料,需要的朋友可以参考下
    2016-05-05
  • 一文了解Java中record和lombok的使用对比

    一文了解Java中record和lombok的使用对比

    Java的 record 关键字是Java 14中引入的一个新的语义特性。Lombok 是一个Java库,可以自动生成一些已知的模式为Java字节码。本文我们将探讨各种使用情况,包括java record 的一些限制。对于每个例子,我们将看到Lombok如何派上用场,并比较这两种解决方案
    2022-07-07
  • Java中的方法、常量、变量、参数用例详解

    Java中的方法、常量、变量、参数用例详解

    在JVM的运转中,承载的是数据,而数据的一种变现形式就是“量”,量分为:常量与变量,我们在数学和物理学中已经接触过变量的概念了,在Java中的变量就是在程序运行过程中可以改变其值的量,这篇文章主要介绍了Java中的方法、常量、变量、参数,需要的朋友可以参考下
    2024-01-01
  • java中如何获取时间戳的方法实例

    java中如何获取时间戳的方法实例

    时间戳通常是一个字符序列,唯一地标识某一刻的时间,所以下面这篇文章主要给大家介绍了关于java中如何获取时间戳的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-11-11

最新评论