-4

I used reduce with stream and parallelStream on the same array with same lambda expression, and I expected the same result but the output is different. However, the results are different and I don't know why.

The code:

    System.out.println("Reduce me...");
    Integer[] arrx = {1,2,3,4};
    //        Reducing the Array

    Arrays
            .stream(arrx)
            .reduce((s1, s2) -> (int)Math.pow(s1,2) + (int)Math.pow(s2,2))
            .ifPresent(System.out::println);

    Arrays.asList(arrx)
            .parallelStream()
            .reduce((s1, s2) -> (int)Math.pow(s1,2) + (int)Math.pow(s2,2))
            .ifPresent(System.out::println);

The output:

1172
650
FlexEast
  • 317
  • 2
  • 13
Jason Foster
  • 117
  • 10
  • Have you researched what the differences are betweet ``stream`` and ``parallelStream``? If you already know that this responsible for the different results... – f1sh Jun 20 '18 at 14:52
  • 1
    Possible duplicate of [Why parallel stream get collected sequentially in Java 8](https://stackoverflow.com/questions/29709140/why-parallel-stream-get-collected-sequentially-in-java-8) – Gatusko Jun 20 '18 at 14:54
  • @Gatusko It may not be an exact duplicate, but there’s certainly a lot to be learned from that question. Thanks for the link. – Ole V.V. Jun 20 '18 at 15:19

2 Answers2

7

Your reduce operation is depend on the encounter order of the array elements.

The parallelStream ignore that order and you received the different value each time you invoke the parallel execution.

Mạnh Quyết Nguyễn
  • 17,677
  • 1
  • 23
  • 51
  • Cool, I got it! Thanks – Jason Foster Jun 20 '18 at 15:18
  • 1
    The parallel stream does *not* ignore the order. It assumes that you are passing an [*associative* function](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Associativity) to reduce, as [mandated by the specification](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#reduce-java.util.function.BinaryOperator-). If you obey the contract, you will get correct results. For example `String::concat` depends on the order of the elements, but is an associative function that works flawlessly with parallel `reduce`. – Holger Jun 21 '18 at 07:49
2

The sequential stream is deterministic, meaning we know which sequence of operations it performs:

1^2 + 2^2 = 1 + 4 = 5
5^5 + 3^2 = 25 + 9 = 34
34^2 + 4^2 = 1156 + 16 = 1172

The parallel stream may reduce elements in any order. The 650 you observed may have come about through these operations:

1^2 + 2^2 = 5
3^2 + 4^2 = 9 + 16 = 25
5^2 + 25^2 = 25 + 625 = 650

Next time you may get a different order and therefore a different result.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161