我想将两个Map与JAVA 8 Stream合并:

Map<String, List<String>> mapGlobal = new HashMap<String, List<String>>();
Map<String, List<String>> mapAdded = new HashMap<String, List<String>>();

我尝试使用此实现:
mapGlobal = Stream.of(mapGlobal, mapAdded)
                .flatMap(m -> m.entrySet().stream())
                .collect(Collectors.groupingBy(Map.Entry::getKey,
                        Collectors.mapping(Map.Entry::getValue,
                                           Collectors.toList())
                ));

但是,此实现只会产生如下结果:
Map<String, List<Object>>
如果mapGlobal中不包含一个键,它将与相应的字符串列表一起添加为新键。如果 key 在mapGlobalmapAdded中重复,则两个值列表将合并为:A = {1, 3, 5, 7}B = {1, 2, 4, 6}然后A ∪ B = {1, 2, 3, 4, 5, 6, 7}

最佳答案

您可以通过遍历mapAdded中的所有条目并将它们合并到mapGlobal中来实现此目的。

下面的代码通过调用 mapAdded 来迭代forEach(action)的条目,其中操作消耗了每个条目的键和值。对于每个条目,我们在merge(key, value, remappingFunction)上调用 mapGlobal :这将在键k下创建条目,并在键不存在的情况下为v值;如果键已经存在,则将调用给定的重映射函数。此函数将2个列表合并,在这种情况下,首先将其添加到TreeSet中,以确保唯一和已排序的元素并转换回列表:

mapAdded.forEach((k, v) -> mapGlobal.merge(k, v, (v1, v2) -> {
    Set<String> set = new TreeSet<>(v1);
    set.addAll(v2);
    return new ArrayList<>(set);
}));

如果要并行运行,可以通过获取entrySet()并在其上调用parallelStream()来创建Stream管道。但是,然后,您需要确保使用支持mapGlobal并发的映射,例如ConcurrentHashMap
ConcurrentMap<String, List<String>> mapGlobal = new ConcurrentHashMap<>();
// ...
mapAdded.entrySet().parallelStream().forEach(e -> mapGlobal.merge(e.getKey(), e.getValue(), (v1, v2) -> {
    Set<String> set = new TreeSet<>(v1);
    set.addAll(v2);
    return new ArrayList<>(set);
}));

07-25 23:58