Detailed explanation and misunderstanding of Java 8 stream reduce

Detailed explanation and misunderstanding of Java 8 stream reduce

brief introduction

The stream API provides some predefined reduce operations, such as count(), max(), min(), sum(). If we need to write the reduce logic ourselves, we can use the reduce method.

This paper will analyze the use of reduce method in detail and give specific examples.

Reduce details

There are three kinds of reduce in the stream class, which accept 1 parameter, 2 parameters and 3 parameters respectively. First, let's look at a parameter:

Optional<T> reduce(BinaryOperator<T> accumulator);

This method accepts a binaryoperator parameter. Binaryoperator is a @ functionalinterface and needs to implement the following methods:

R apply(T t,U u);

The accumulator tells the reduce method how to accumulate the data in the stream.

for instance:

List<Integer> intList = Arrays.asList(1,2,3);
        Optional<Integer> result1=intList.stream().reduce(Integer::sum);
        log.info("{}",result1);

The output result of the above example:

com.flydean.ReduceUsage - Optional[6]

An example of a parameter is very simple. No more here.

Next, let's take another look at two examples of parameters:

T reduce(T identity,BinaryOperator<T> accumulator);

This method takes two parameters: identity and accumulator. There is one more parameter identity.

Maybe someone in some articles tells you that identity is the initialization value of reduce, which can be specified arbitrarily, as shown below:

Integer result2=intList.stream().reduce(100,Integer::sum);
        log.info("{}",result2);

In the above example, the value we calculated is 106.

If we change the stream to parallel stream:

Integer result3=intList.parallelStream().reduce(100,result3);

The result is 306.

Why 306? Because in parallel computing, the initial cumulative value of each thread is 100, and the result of the last three threads is 306.

The results of parallel computing and non parallel computing are different. This is certainly not a problem with JDK. Let's take another look at the description of identity in JDK:

So it is wrong for us to pass in 100 here, because sum (100 + 1)! = 1.

Here, the identity of sum method can only be 0.

If we use 0 as the identity, the results calculated by stream and parallel stream are the same. This is the real intention of identity.

Let's look at the methods of three parameters:

<U> U reduce(U identity,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner);

Different from the previous method, a combiner is added, which is used to combine the results of multithreaded computing.

You may have noticed why the type of accumulator is bifunction and the type of combiner is binaryoperator?

public interface BinaryOperator<T> extends BiFunction<T,T,T>

Binaryoperator is a sub interface of bifunction. The apply method to be implemented is defined in bifunction.

In fact, the implementation of the lower level method of reduce only uses the apply method and does not use other methods in the interface, so I guess the difference here is just for simple distinction.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>