作为比较的基准,这里是常规版本:
<T> EnumMap<E1,EnumMap<E2,T>> buildTheMap(E1[] e1values,
E2[] e2values,
BiFunction<E1,E2,T> f) {
EnumMap<E1,EnumMap<E2,T>> outer = new EnumMap<>(E1.class);
for (E1 e1 : e1values) {
EnumMap<E2,T> inner = new EnumMap<>(E2.class);
for (E2 e2 : e2values) {
inner.put(e2, f.apply(e1, e2));
}
outer.put(e1, inner);
}
return outer;
}
现在这是一个使用嵌套三参数形式的collect()
流终端操作的版本:
<T> EnumMap<E1,EnumMap<E2,T>> buildTheMap(E1[] e1values,
E2[] e2values,
BiFunction<E1,E2,T> f) {
return
Stream.of(e1values)
.collect(() -> new EnumMap<>(E1.class),
(map, e1) -> map.put(e1, Stream.of(e2values)
.collect(() -> new EnumMap<>(E2.class),
(m, e2) -> m.put(e2, f.apply(e1, e2)),
Map::putAll)),
Map::putAll);
}
使这变得麻烦的是外部收集器的累加器函数必须使用自己的三参数收集器运行一个流来生成内部映射。这真的很难缩进。我没有为每个collect()
调用排列三个参数,而不是标准间距。这使它非常宽,但如果我不这样做,由于嵌套太深,很难看出什么是什么。尽管我是流媒体的粉丝,但我很难说这比传统版本更好。
你可能会说,“为什么不用toMap()
三参数collect()
函数来代替呢?” 问题是我们需要创建EnumMap
实例,并且toMap()
需要地图供应商的重载有四个参数:
toMap(keyFunc, valueFunc, mergeFunc, mapSupplier)
更糟糕的是,没有使用合并函数(第三个参数),所以我们必须提供一个从未使用过的函数。看起来是这样的:
<T> EnumMap<E1,EnumMap<E2,T>> buildTheMap(E1[] e1values,
E2[] e2values,
BiFunction<E1,E2,T> f) {
return
Stream.of(e1values)
.collect(toMap(e1 -> e1,
e1 -> Stream.of(e2values)
.collect(toMap(e2 -> e2,
e2 -> f.apply(e1, e2),
(x, y) -> x,
() -> new EnumMap<>(E2.class))),
(x, y) -> x,
() -> new EnumMap<>(E1.class)));
}
在我看来并没有更好。我的钱仍然在传统版本上。
可以尝试多种替代方法。我们将看看一夜好眠会带来什么。