Collectors.toMap()的第三个参数是合并函数,用于处理重复key时新旧value的合并逻辑,接收旧值和新值并返回合并结果,常见策略包括保留首个、取最大值、拼接字符串或构建集合。
Collectors.toMap() 的第三个参数是合并函数,专门解决重复 key 场景
当列表里多个元素生成相同的
结果时,
默认会抛出
。第三个参数(即
)就是用来定义“遇到重复 key 时,新旧 value 怎么合并”的逻辑。
它接收两个参数:第一个是已存在的 value(旧值),第二个是当前要插入的 value(新值),返回合并后的结果。
不传第三个参数 → 直接报错
传了但逻辑返回
→ 可能导致
(取决于后续使用)
合并函数必须是无副作用、幂等的;否则并发流中行为不可预测
常见合并策略:保留第一个、取最大值、拼接字符串、构造集合
实际开发中,合并方式取决于业务语义。比如日志去重取最早时间、统计指标取最新值、多标签合并成列表等。
以下是一些典型写法示例:
立即学习
“
Java免费学习笔记(深入)
”;
注意泛型推导和 null 值处理
的三个重载方法中,只有带
的那个支持自动推导泛型;但一旦 value 类型可能为
,就要格外小心——
的两个参数都可能是
,直接调用方法会 NPE。
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
如果 key 对应的 value 允许为
,合并函数里必须显式判空,例如:
若用
指定 map 工厂,要注意
允许
key/value,而
不允许
value
流为空时,
返回空 map,不会触发 merge 函数
比 toMap() 更适合“多对一聚合”的替代方案:groupingBy + mapping
当你本质不是想“转 Map”,而是想“按 key 分组并聚合 value”,比如把同名用户收集成列表、求平均分、取最新记录,用
配合下游收集器更清晰、更安全。
例如:
这种写法天然规避键冲突问题,语义明确,且下游收集器(如
、
)已内建健壮逻辑。
真正需要
第三个参数的场景,往往是“必须一对一映射,且冲突有明确覆盖规则”,比如缓存预热时以最后写入为准。这时候 merge 函数不能只图写得短,得想清楚旧值和新值哪个更“权威”。
keyMapperCollectors.toMap()IllegalStateException: Duplicate keymergeFunctionnullNullPointerException// 保留第一个出现的 value(等价于 LinkedHashMap.putIfAbsent 的语义)
Map map1 = list.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getAge,
(oldVal, newVal) -> oldVal // 丢弃新值
));
// 取年龄较大者
Map map2 = list.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getAge,
Integer::max
));
// 拼接多个邮箱(假设 value 是 String)
Map map3 = list.stream()
.collect(Collectors.toMap(
User::getUid,
User::getEmail,
(e1, e2) -> e1 + ";" + e2
));
// 收集为 List(需配合 toMap 的泛型声明)
Map> map4 = list.stream()
.collect(Collectors.toMap(
Person::getName,
p -> Arrays.asList(p),
(list1, list2) -> {
List merged = new ArrayList<>(list1);
merged.addAll(list2);
return merged;
}
)); toMap()mergeFunctionnullmergeFunctionnullnull(v1, v2) -> (v1 == null) ? v2 : (v2 == null) ? v1 : v1 + v2Collectors.toMap(keyMapper, valueMapper, mergeFunc, HashMap::new)HashMapnullConcurrentHashMapnulltoMapCollectors.groupingBy()// 同名用户聚合为 List —— 比手动写 mergeFunction 更直观
Map> grouped = list.stream()
.collect(Collectors.groupingBy(Person::getName));
// 取每个名字对应的最大年龄
Map maxAges = list.stream()
.collect(Collectors.groupingBy(
Person::getName,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(Person::getAge)),
opt -> opt.map(Person::getAge).orElse(null)
)
)); summingIntaveragingDoubletoMap