- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java8 Collectors.toMap的坑由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
按照常规思维,往一个map里put一个已经存在的key,会把原有的key对应的value值覆盖,然而通过一次线上问题,发现Java8中的Collectors.toMap反其道而行之,它默认给抛异常,抛异常... 。
线上业务代码出现Duplicate Key的异常,影响了业务逻辑,查看抛出异常部分的代码,类似以下写法:
1
|
Map<Integer, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName));
|
然后list里面有id相同的对象,结果转map的时候居然直接抛异常了。。查源码发现toMap方法默认使用了个throwingMerger 。
1
2
3
4
5
6
7
8
9
10
|
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是哪里用的呢?
1
2
3
4
5
6
7
8
9
10
|
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方法里面有这么一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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的做法就是抛了个异常。所以到这里就可以知道写的代码为什么呲了。.
如果不想抛异常的话,自己传进去一个方法即可,上述代码可以改成:
1
|
Map<Integer, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName,(oldValue, newValue) -> newValue));
|
这样就做到了使用新的value替换原有value.
写代码调方法时,多看源码实现,注意踩坑! 。
到此这篇关于Java8 Collectors.toMap的坑的文章就介绍到这了,更多相关Java8 Collectors.toMap内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/u013805360/article/details/82686009 。
最后此篇关于Java8 Collectors.toMap的坑的文章就讲到这里了,如果你想了解更多关于Java8 Collectors.toMap的坑的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
前言 每日站会(Daily Standup)是团队统一节奏的、在固定时间发生的、帮助团队内部快速同步进展的敏捷实践活动: 站会的目的是让团队能更好地对齐 Sprint 目标;
jdbcTemplate 中的queryForList,你真的懂吗? 你想象中的queryForList是不是应该长成下面这种模样? String sql = "select *
python是一门清晰简洁的语言,如果你对一些细节不了解的话,就会掉入到那些深不见底的“坑”里,下面,我就来总结一些python里常见的坑。 列表创建和引用 嵌套列表的创建 使用*号来创建一个
如今,在DevOps当中建立安全体系显得比以往任何时候都更加重要。《2021年企业DevOps技能提升报告》指出,56%的受访者表示DevSecOps已经成为自动化工具中的一大必备要素。然而,D
前言 相信看到这个题目,可能大家都觉得是一个老生常谈的月经topic了。一直以来其实把握一个“值传递”基本上就能理解各种情况了,不过最近遇到了更深一点的“小坑”,与大家分享一下。 首先还是从最简
前言 Go 中的for range组合可以和方便的实现对一个数组或切片进行遍历,但是在某些情况下使用for range时很可能就会被"坑",下面用一段代码来模拟下:
大家好,我是明哥。 在开始之前,先考你一个非常 Go 味的经典问题:如何判断一个 interface{} 的值是否为 nil ? 这也是面试有可能会被问到的一个问题,这个问题很 “迷”,平时
ava并发包有很大一部分内容都是关于并发容器的,因此学习和搞懂这部分的内容很有必要。 Java 1.5 之前提供的同步容器虽然也能保证线程安全,但是性能很差,而 Java 1.5 版本之后提供的并发
大家好,我是煎鱼。 前几天在读者交流群里看到一位小伙伴,针对 interface 的使用有了比较大的疑惑。 无独有偶,我也在网上看到有小伙伴在 Go 面试的时候被问到了:
我是一名优秀的程序员,十分优秀!