【问题标题】:Is mergeFunction of Collectors.toMap allowed to modify its arguments?Collectors.toMap 的 mergeFunction 是否允许修改其参数?
【发布时间】:2016-01-27 20:45:37
【问题描述】:

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

(existingMap, newMap) -> {
    existingMap.putAll(newMap);
    return existingMap;
}

代码似乎暂时可以工作,但我觉得我没有按预期使用Collectors.toMap(...),因为我正在改变累加器和组合器中的值。

这里是完整的代码 sn-p:

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

【问题讨论】:

  • 您实际上是在修改流源中的地图,这真的是您想要的吗?

标签: lambda java-8 collectors


【解决方案1】:

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

通常,如果此输入是在流操作期间创建的结果,则通过修改其中一个输入进行合并可以正常工作,例如由收藏家自己。您可以通过将Entry::getValue 函数替换为e -> new HashMap<>(e.getValue()) 轻松实现此目的。这样就保证了merge操作的不干涉和map的可变性,但是会比在merge函数保存中不创建map会创建更多的临时map。

或者,您可以使用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;})));

这不会修改任何source map,只会创建一个可变的result map,所以合并的时候可以放进去。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2017-12-22
      • 2015-12-22
      • 2012-04-18
      • 1970-01-01
      • 2011-09-17
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 2014-09-18
      相关资源
      最近更新 更多