What is the Java 8 reduce BinaryOperator used for?

binary-operators, java, java-8

Solution

The method `reduce` in the interface `Stream` is overloaded. The parameters for the method with three arguments are:

- identity

- accumulator

- combiner

The `combiner` supports parallel execution. Apparently, it is not used for sequential streams. However, there is no such guarantee. If you change your streams into parallel stream, I guess you will see a difference:

Stream<String>stringStream = Stream.of(
    "John Lennon", "Paul Mccartney", "George Harrison", "Ringo Starr")
    .parallel();

Here is an example of how the `combiner` can be used to transform a sequential reduction into a reduction, that supports parallel execution. There is a stream with four `String`s and `acc` is used as an abbreviation for `accumulator.apply`. Then the result of the reduction can be computed as follows:

acc(acc(acc(acc(identity, "one"), "two"), "three"), "four");

With a compatible `combiner`, the above expression can be transformed into the following expression. Now it is possible to execute the two sub-expressions in different threads.

combiner.apply(
    acc(acc(identity, "one"), "two"),
    acc(acc(identity, "three"), "four"));

Regarding your second question, I use a simplified `accumulator` to explain the problem:

BiFunction<StringBuilder,String,StringBuilder> accumulator =
    (builder,name) -> builder.append(name);

According to the Javadoc for Stream::reduce, the `accumulator` has to be associative. In this case, that would imply, that the following two expressions return the same result:

acc(acc(acc(identity, "one"), "two"), "three")  
acc(acc(identity, "one"), acc(acc(identity, "two"), "three"))

That's not true for the above `accumulator`. The problem is, that you are mutating the object referenced by `identity`. That's a bad idea for the `reduce` operation. Here are two alternative implementations which should work:

// identity = ""
BiFunction<String,String,String> accumulator = String::concat;

// identity = null
BiFunction<StringBuilder,String,StringBuilder> accumulator =
    (builder,name) -> builder == null
        ? new StringBulder(name) : builder.append(name);

Problem

I am currently reading the O'Reilly Java 8 Lambdas, it is a really good book. I came across with a example like this. I have a ``` private final BiFunction<StringBuilder,String,StringBuilder>accumulator= (builder,name)->{if(builder.length()>0)builder.append(",");builder.append("Mister:").append(name);return builder;}; final Stream<String>stringStream = Stream.of("John Lennon","Paul Mccartney" ,"George Harrison","Ringo Starr"); final StringBuilder reduce = stringStream .filter(a->a!=null) .reduce(new StringBuilder(),accumulator,(left,right)->left.append(right)); System.out.println(reduce); System.out.println(reduce.length()); ``` this produce the right output. `Mister:John Lennon,Mister:Paul Mccartney,Mister:George Harrison,Mister:Ringo Starr` My question is regarding the `reduce` method the last parameter which is a `BinaryOperator`. Which this parameter is used for? If I change by ``` .reduce(new StringBuilder(),accumulator,(left,right)->new StringBuilder()); ``` the output is the same; if I pass `NULL` then N.P.E is returned. What is this parameter used for? Update Why if I run it on `parallelStream` I am receiving different results? First run: ``` returned StringBuilder length = 420 ``` Second run: ``` returned StringBuilder length = 546 ``` Third run: ``` returned StringBuilder length = 348 ``` and so on. Why is this - should it not return all the values at each iteration?

Original source

Related problems