Lambda 是否允许Collectors.toMap的mergeFunction修改其参数?

Lambda 是否允许Collectors.toMap的mergeFunction修改其参数?,lambda,java-8,collectors,Lambda,Java 8,Collectors,我有一个嵌套映射流stream,我想通过转换成一个条目集流并调用Collectors.toMap(…)来组合(使用外部键;假设内部键是唯一的)。为了确保具有重复外部键的贴图正确组合,我将以下BinaryOperator传递到toMap(…)函数: (existingMap, newMap) -> { existingMap.putAll(newMap); return existingMap; } 代码似乎暂时可以工作,但我觉得我没有按预期使用Collectors.toM

我有一个嵌套映射流
stream
,我想通过转换成一个条目集流并调用
Collectors.toMap(…)
来组合(使用外部键;假设内部键是唯一的)。为了确保具有重复外部键的贴图正确组合,我将以下
BinaryOperator
传递到
toMap(…)
函数:

(existingMap, newMap) -> {
    existingMap.putAll(newMap);
    return existingMap;
}
代码似乎暂时可以工作,但我觉得我没有按预期使用
Collectors.toMap(…)
,因为我正在改变累加器和组合器中的值

以下是完整的代码片段:

mapsToCombine.flatMap(map -> map.entrySet().stream()).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (existingMap, newMap) -> {
    existingMap.putAll(newMap);
    return existingMap;
}));

似乎没有明确指定,但在当前的实现中,这样做是完全安全的。

您应该知道,您正在修改的映射与源流中包含的映射完全相同,因此如果您的流是从数据结构(例如集合)构建的,此数据结构将在操作后以不可预测的方式进行修改。它还意味着,如果源多次包含同一个map实例(这将是违反非干扰规则的情况),则整个操作可能会中断。或者如果源映射是不可变的。更糟糕的是,它可能多次运行而没有问题,并且突然中断,在调试期间可能无法再现

通常,如果此输入是流操作期间(例如由收集器本身)创建的结果,则通过修改其中一个输入进行合并效果良好。通过将
Entry::getValue
函数替换为
e->newhashmap(e.getValue())
,可以轻松实现这一点。然后,可以保证合并操作的不干扰性和映射的易变性,但它将创建比不在合并函数中创建映射更多的临时映射

或者,您可以使用
groupingBy
,它允许您为以下值指定收集器:

Map<String, Map<String, String>> result
  = mapsToCombine.flatMap(map -> map.entrySet().stream())
    .collect(Collectors.groupingBy(Entry::getKey, Collector.of(HashMap::new,
     (m,e) -> m.putAll(e.getValue()), (m1,m2) -> { m1.putAll(m2); return m1;})));
映射结果
=mapsToCombine.flatMap(映射->映射.entrySet().stream())
.collect(Collector.groupingBy)(条目::getKey,Collector.of)(HashMap::new,
(m,e)->m.putAll(e.getValue(),(m1,m2)->{m1.putAll(m2);返回m1;}));

这不会修改任何源映射,但只会创建一个可变结果映射,因此您可以在合并时将其放入其中。

这样做实际上是在修改流源中的映射,这真的是您想要的吗?