Java8 streams sequential and parallel execution produce different results?

前端 未结 3 1709
逝去的感伤
逝去的感伤 2020-12-05 06:17

Running the following stream example in Java8:

    System.out.println(Stream
        .of(\"a\", \"b\", \"c\", \"d\", \"e\", \"f\")
        .reduce(\"\", (s1,         


        
3条回答
  •  甜味超标
    2020-12-05 06:59

    From reduce's documentation:

    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 not true in your case - "" and "a" creates "/a".

    I have extracted the accumulator function and added a printout to show what happens:

    BinaryOperator accumulator = (s1, s2) -> {
        System.out.println("joining \"" + s1 + "\" and \"" + s2 + "\"");
        return s1 + "/" + s2;
    };
    System.out.println(Stream
                    .of("a", "b", "c", "d", "e", "f")
                    .parallel()
                    .reduce("", accumulator)
    );
    

    This is example output (it differs between runs):

    joining "" and "d"
    joining "" and "f"
    joining "" and "b"
    joining "" and "a"
    joining "" and "c"
    joining "" and "e"
    joining "/b" and "/c"
    joining "/e" and "/f"
    joining "/a" and "/b//c"
    joining "/d" and "/e//f"
    joining "/a//b//c" and "/d//e//f"
    /a//b//c//d//e//f
    

    You can add an if statement to your function to handle empty string separately:

    System.out.println(Stream
            .of("a", "b", "c", "d", "e", "f")
            .parallel()
            .reduce((s1, s2) -> s1.isEmpty()? s2 : s1 + "/" + s2)
    );
    

    As Marko Topolnik noticed, checking s2 is not required as accumulator doesn't have to be commutative function.

提交回复
热议问题