Java Stream
的{{3}}:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
有助于根据流中对象的某些属性来减少流。
然而,我不清楚为什么accumulator
不能更直接并且服务于同一目的:
BiFunction<U, T, U> accumulator
。
accumulator
签名中的通配符提供了哪些额外的灵活性(以降低可读性为代价)?
答案 0 :(得分:6)
为什么累加器不能更直接并且用于相同的目的:
它可能会比需要更具限制性。如果你说了
BiFunction<String, Object, String> accumulator = (a,b) -> a + b;
您应该可以将其传递给
String join = strings.stream().reduce("text: ", accumulator, (a, b) -> a + b);
或
String join = ints.stream().reduce("long num: ", accumulator, (a, b) -> a + b);
即。你可以为一次减少写一个累加器。
答案 1 :(得分:3)
它允许使用函数或lambda,其中第二个参数类型不需要是流的精确类型T
,但可以是其任何超类型。这允许:
创建能够在不同类型的流中使用的累加器
用作累加器的现有方法接受T
的超类型。
例如,您可以使用接受Stream<Integer>
的{{1}}累加器,或接受Number
甚至Stream<String>
的{{1}}累加器。
更重要的是,这遵循常见的JDK API样式:在每个签名中,可以使用更窄或更宽的类型,应该使用它。我从未看到过这条规则,但我不知道JDK中这条规则的任何例外。
有关更好的解释,请参阅What is PECS SO question。
例如,累加器计算任何流的不同项目,可能如下所示:
CharSequence
可以用于Object
,如下所示:
public class DistinctCounter {
Set<Object> set = new HashSet<>();
// count() accepts object of any type
public int count(int prev, Object item) {
return prev + set.add(item) ? 1 : 0;
}
}
虽然这个例子不太实用,但希望它有助于理解。