Java8 Collectors.toMap的坑
2021-03-18 12:36:24
按照常规思维,往一个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内容请搜索IT技术网以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT技术网!
您可能感兴趣的文章:
- 解决JAVA8 Collectors.toMap value为null报错的问题
相关阅读
- Java8的Lambda表达式你真的会吗
- Java8 Instant时间戳使用小记
- JAVA8 的StringJoiner 使用及原理解析
- Java8使用stream实现list中对象属性的合并(去重并求和)
- java8中Map的一些骚操作总结
- Java8 使用流抽取List<T>集合中T的某个属性操作
- java8 实现提取集合对象的每个属性
- Java8 实现stream将对象集合list中抽取属性集合转化为map或list
- java8新特性 获取list某一列的操作
- Java8 Optional的详细使用教程
- Java8 Collectors求和功能的自定义扩展操作
- Java8中forEach语句循环一个List和Map
- Java8优雅的字符串拼接工具类StringJoiner实例代码
- Java8新特性之方法引用的实践指南
- Java8 将List转换为用逗号隔开的字符串的多种方法
- java8中的Collectors.groupingBy用法详解
- java8实现List中对象属性的去重方法
- java8 stream多字段排序的实现