Stream.reduce的累加器参数中通配符的用途是什么?

时间:2016-03-18 11:56:46

标签: java generics java-8

Java Stream的{​​{3}}:

<U> U reduce(U identity,
             BiFunction<U, ? super T, U> accumulator,
             BinaryOperator<U> combiner);

有助于根据流中对象的某些属性来减少流。

然而,我不清楚为什么accumulator不能更直接并且服务于同一目的:

BiFunction<U, T, U> accumulator

accumulator签名中的通配符提供了哪些额外的灵活性(以降低可读性为代价)?

2 个答案:

答案 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;
     }
 }

虽然这个例子不太实用,但希望它有助于理解。