2

我有一个Stream<Map<String, Map<String, String>>>要组合的嵌套映射流(使用外部键;假设内部键是唯一的),方法是转换为条目集流并调用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;
}));
4

2 回答 2

3

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

通常,如果此输入是在流操作期间(例如由收集器本身创建)创建的结果,则通过修改其中一个输入进行合并可以正常工作。您可以通过将Entry::getValue函数替换为e -> new HashMap<>(e.getValue()). 然后,保证了合并操作的不干扰和地图的可变性,但是它会创建更多的临时地图而不是在合并函数保存中创建地图。

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

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;})));

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

于 2016-01-27T12:45:37.390 回答
2

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

于 2016-01-27T07:10:33.410 回答