给定一些地图,是否有一种方法将它们所有的条目放入一个地图中?
假设不考虑空值、覆盖条目等问题,我想编写的代码如下:
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表达式中调用累加器上的方法并返回它?
reduce
的这种方式基本上是有问题的:在序列执行时可能有效,但在并行执行时会出错。这是因为 reduce() 方法将其第一个(身份)参数视为可重复使用的值。因此它适用于原始类型和不可变类型,但是对于可变值(如new HashMap<>()
)在并行流中将被不同的线程同时进行修改,这可能导致出现问题。解决方法是使用collect()
,就像 @Pshemo 的答案中所示。 - Maurice Naftalin