在Stream reduce方法中,求和必须始终为0,乘法必须始终为1吗?乘法、方法、Stream、reduce

2023-09-07 09:48:11 作者:懂我不必说出来@

我继续学习 java 8.

I proceed with java 8 learning.

我发现了一个有趣的行为:

I have found an interesting behavior:

让我们看看代码示例:

// identity value and accumulator and combiner
Integer summaryAge = Person.getPersons().stream()
        //.parallel()  //will return surprising result
        .reduce(1,
                (intermediateResult, p) -> intermediateResult + p.age,
                (ir1, ir2) -> ir1 + ir2);
System.out.println(summaryAge);

和模型类:

public class Person {

    String name;

    Integer age;
    ///...

    public static Collection<Person> getPersons() {
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("Vasya", 12));
        persons.add(new Person("Petya", 32));
        persons.add(new Person("Serj", 10));
        persons.add(new Person("Onotole", 18));
        return persons;
   }
}

12+32+10+18 = 72.对于顺序流,此代码始终返回 73,即 72 + 1,但对于并行,它始终返回 76,即 72 +4*1(4 等于流元素数).

12+32+10+18 = 72. For sequential stream, this code always returns 73 which is 72 + 1 but for parallel, it always returns 76 which is 72 + 4*1 (4 is equal to stream elements count).

当我看到这个结果时,我认为并行流和顺序流返回不同的结果很奇怪.

When I saw this result I thought that it is strange that parallel stream and sequential streams return different results.

我是不是在什么地方违约了?

Am I broke contract somewhere?

对我来说,73 是预期结果,但 76 不是.

for me, 73 is expected result but 76 is not.

推荐答案

identity值是一个值,使得x op identity = x.这不是 Java Stream 所独有的概念,例如参见 on Wikipedia.

The identity value is a value, such that x op identity = x. This is a concept which is not unique to Java Streams, see for example on Wikipedia.

它列出了一些标识元素的例子,其中一些可以直接用Java代码表示,例如

It lists some examples of identity elements, some of them can be directly expressed in Java code, e.g.

reduce("", String::concat)reduce(true, (a,b) -> a&&b)reduce(false, (a,b) -> a||b)reduce(Collections.emptySet(),(a,b)->{设置<X>s=新哈希集<>(a);s.addAll(b);返回 s;})reduce(Double.POSITIVE_INFINITY, Math::min)reduce(Double.NEGATIVE_INFINITY, Math::max)

应该清楚的是,任意x的表达式x + y == x只能在y==0时满足,因此 0 是加法的标识元素.同样,1 是乘法的标识元素.

It should be clear that the expression x + y == x for arbitrary x can only be fulfilled when y==0, thus 0 is the identity element for the addition. Similarly, 1 is the identity element for the multiplication.

更复杂的例子是

减少谓词流

Reducing a stream of predicates

reduce(x->true, Predicate::and)
reduce(x->false, Predicate::or)

Stream流学习

减少函数流

Reducing a stream of functions

reduce(Function.identity(), Function::andThen)