Isn't it guaranteed that a parallel stream derived from a list will always behave like its sequential counterpart giving the same, predictable output?

Viewed 204

The following code prints true for 100 times:

for(int i=0; i<100; i++) {
   String s2 = Arrays.asList("A", "E", "I", "O", "U").parallelStream().reduce("x", String::concat, String::concat);
   System.out.println("xAxExIxOxU".equals(s2));
}

Granted, 100 times is not a guarantee. But doesn't it seem though that even if the identity used here does not meet the requirement "...for all u, combiner.apply(identity, u) is equal to u" per the doc, we can still say that a parallel stream derived from a list or any other inherently ordered structure will behave just like a sequential stream in reduce() returning the same output?

1 Answers

The Javadoc for the Stream.reduce function with an identity argument says:

The identity value must be an identity for the accumulator function. This means that for all t, accumulator.apply(identity, t) is equal to t.

Which is clearly not the case here - "x".concat(anything) doesn't equal anything. The only valid identity value here is "".

If you had tested the premise of the title of your question - by seeing what a non-parallel operation returns - you'd see that the answer to your title is "no" - because a non-parallel stream returns "xAEIOU" for your reduce operation.

If you change the identity value from "x" to "", then the answer would be "yes, there is such a guarantee, as your reduce function is associative and the constraints on the identity value are also satisfied."

Even with your modified title, the answer is clear:

You are breaking the contract of the reduce function by providing, as the identity value, a value that is not an identity value for your reduce function. As such, since you are breaking the contract of the reduce methods, all guarantees are off.

It's easy to create a case where it doesn't hold; just make your list larger like Holger already pointed out:

List<String> list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
    list.add("A");
}
String s2 = list.parallelStream().reduce("x", String::concat, String::concat);
System.out.println(s2);
if (s2.length() != list.size() * 2) {
    System.out.println("Bad s2 size");
}
Related