Combiner 永远不会在缩减操作中被调用(但是是强制性的)

Combiner never gets called in reduction operation (but is mandatory)

我想弄清楚累加器和组合器在 reduce 流操作中的作用。

    List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));

    int result = users.stream()
            .reduce(0,
                    (partialAgeResult, user) -> {
                        // accumulator is called twice
                        System.out.println(MessageFormat.format("partialAgeResult {0}, user {1}", partialAgeResult, user));
                        return partialAgeResult + user.getAge();
                    },
                    (integer, integer2) -> {
                        // combiner is never called
                        System.out.println(MessageFormat.format("integer {0}, integer2 {1}", integer, integer2));
                        return integer * integer2;
                    });

    System.out.println(MessageFormat.format("Result is {0}", result)); 

我注意到组合器从未执行过,结果是 65。 如果我使用 users.parallelStream() 然后组合器执行一次,结果是 1050.

为什么 streamparallelStream 会产生不同的结果?我没有看到并行执行它的任何副作用。

简单流版本中组合器的用途是什么?

问题就在这里。您正在乘法而不是在您的组合器中添加。

 (integer, integer2) -> {
                        // combiner is never called
                        System.out.println(MessageFormat.format("integer {0}, integer2 {1}", integer, integer2));
                        return integer * integer2; //<----- Should be addition
                    });

组合器用于适当组合并行操作的各个部分,因为这些操作可以独立地对原始流的各个“部分”执行。

一个简单的例子就是对元素列表求和。并行操作中可能有多种部分和,因此需要在组合器中对部分和进行求和以获得总和(一个很好的练习,你自己试试看)。

对于累加器参数或实现类型之间不匹配的顺序流 ( BiFunction<U,? super T,U>),您必须提供组合器但从未调用过,因为您不需要组合部分结果并行计算。

因此您可以通过在 reduce 之前转换为部分数据来简化此操作,以避免给出组合器。

users.stream().map(e -> e.getAge()).reduce(0, (a, b) -> a + b);

所以,对于顺序流,使用像 BiFunction<U,? super T,U> 这样的带有累加器的组合器实际上是没有意义的,但是你必须提供,因为没有像

这样的方法
reduce(U identity, BiFunction<U,? super T,U> accumulator)

但是对于并行流合并器调用。 你得到 1050 因为你乘以组合器意味着 (30*35).