有没有一种优雅的方法可以将地图流减少到一个地图

时间:2014-10-23 23:20:59

标签: java lambda java-8 reduce

鉴于一些地图,是否有一种将所有条目放入一张地图的单行方式?

忽略空值,覆盖条目等问题,我想编码的是:

public static <K, V> Map<K, V> reduce(Map<K, V>... maps) {
    return Arrays.stream(maps)
        .reduce(new HashMap<K, V>(), (a, b) -> a.putAll(b));
}

但是这会产生编译错误,因为a.putAll(b)void。如果它返回this,它将起作用。

要解决这个问题,我编码:

public static <K, V> Map<K, V> reduce(Map<K, V>... maps) {
    return Arrays.stream(maps)
        .reduce(new HashMap<K, V>(), (a, b) -> {a.putAll(b); return a;});
}

编译和工作,但它是一个丑陋的lambda;编码return a;感觉多余。

一种方法是重构实用方法:

public static <K, V> Map<K, V> reduce(Map<K, V> a, Map<K, V> b) {
    a.putAll(b);
    return a;
}

清理lambda:

public static <K, V> Map<K, V> reduce(Map<K, V>... maps) {
    return Arrays.stream(maps)
       .reduce(new HashMap<K, V>(), (a, b) -> reduce(a, b));
}

但是现在我有一个虽然可以重复使用的,有些无用的实用方法。

是否有更优雅的方法在累加器上调用方法并且在lambda中返回它?

1 个答案:

答案 0 :(得分:14)

reduce

类似
U result = identity;
for (T element : this stream)
    result = accumulator.apply(result, element)
return result;

这意味着代表accumulator.apply的lambda需要return结果(最终或中间的)。

如果您想避免此行为,请使用更像

collect
R result = supplier.get();
for (T element : this stream)
    accumulator.accept(result, element);
return result;

所以代表accumulator.accept的lambda不需要return任何值,而是根据result修改element

示例:

public static <K, V> Map<K, V> reduce(Map<K, V>... maps) {
    return Arrays.stream(maps)
            .collect(HashMap::new, Map::putAll, Map::putAll);
            //                          ^            ^
            //                          |         collect results from parallel streams
            //                       collect results in single thread
}