Java Streams – the reduce method

Read Time:4 Minute, 31 Second

I’m going to describe another useful method from Stream package. The reduce method is called on a stream and returns us some value. For instance, we have a range from 1 to 15 and using functional like approach we can easily get a sum of all the numbers within range, multiplying each element (except the first one – I will explain why, in the next paragraph) by 3 using reduce method.

package app;

import java.util.stream.IntStream;

public class StreamsReduceExample {
    public static void main(String[] args) {


        int theSum = IntStream.rangeClosed(1,15)
                .reduce((x,y) -> x+3*y).orElse(0);


        System.out.println(theSum);
    }
}

Output:

358

The reduce method from IntStream class has two overloaded versions:
OptionalInt reduce(IntBinaryOperator op) and int reduce(int identity, IntBinaryOperator op)

The first one takes an IntBinaryOperator which means it takes two parameters and has one output parameter (more on that matter you can read in my article about Functions). The method returns and OptionalInt that’s why I had to call orElse(0) to get an int value – if the stream was empty, it would have given us 0.

In the given example the reduce method took a function (x, y) -> x+3*y as a parameter and returned an OptionalInt from which I ‘took’ an int.

Functions – accumulators and cycles

Here, let me tell you a little bit about what happened under the hood and how the calculations were carried out. This is an approach borrowed from functional languages like eg. Scala or Ruby (a functional programming paradigm langs). I will also explain why the first value in the given example was not tripled.

The method OptionalInt reduce(IntBinaryOperator op) takes IntBinaryOperator as a parameter. I have passed there (x, y) -> x+3*y so in the first iteration variable x took the value 1 (first from the range) and y took 2. But according to the function I created: x+3*y – it’s only the second variable that is multiplied by 3. The first one x is the accumulator which stores the result of binary operator while y takes next values given by the stream.

Here I will show you how the function works by printing out each step:

        int theSumWithPrinting = IntStream.rangeClosed(1, 15)
                .reduce((x, y) -> {
                    System.out.printf("accumulator x=%d, next value y=%d\n", x, y);
                    return x + y * 3;
                }).orElse(0);

        System.out.println("Result: " + theSumWithPrinting);

Output:

accumulator x=1, next value y=2
accumulator x=7, next value y=3
accumulator x=16, next value y=4
accumulator x=28, next value y=5
accumulator x=43, next value y=6
accumulator x=61, next value y=7
accumulator x=82, next value y=8
accumulator x=106, next value y=9
accumulator x=133, next value y=10
accumulator x=163, next value y=11
accumulator x=196, next value y=12
accumulator x=232, next value y=13
accumulator x=271, next value y=14
accumulator x=313, next value y=15
Result: 358

I hope it started to make sense now 🙂 Look at the changed code also. I have added printing method to the function and used key word return to return the value. This is regular method so you can execute (almost) any code as long as you return value of correct type (in this case an int).

Because of the fact that the first element was not taken under consideration we have an overloaded method
int reduce(int identity, IntBinaryOperator op) that I mentioned at the beginning. It takes additional identity parameter and uses it as the first value so that the first value provided by the stream is tripled. This method returns us int value so I can remove orElse(0) call.

Example:

    int theSumWithPrinting = IntStream.rangeClosed(1, 15)
                .reduce(0, (x, y) -> {
                    System.out.printf("accumulator x=%d, next value y=%d\n", x, y);
                    return x + y * 3;
                });

        System.out.println("Result: " + theSumWithPrinting);
Output:
accumulator x=0, next value y=1
 accumulator x=3, next value y=2
 accumulator x=9, next value y=3
 accumulator x=18, next value y=4
 accumulator x=30, next value y=5
 accumulator x=45, next value y=6
 accumulator x=63, next value y=7
 accumulator x=84, next value y=8
 accumulator x=108, next value y=9
 accumulator x=135, next value y=10
 accumulator x=165, next value y=11
 accumulator x=198, next value y=12
 accumulator x=234, next value y=13
 accumulator x=273, next value y=14
 accumulator x=315, next value y=15
 Result: 360

One last example. We can use built-in methods to sum or find max value of given stream:

 int theMinValueUsingStaticReference = IntStream.of(2,45,2,0,102,34,99)
                .reduce(Integer.MIN_VALUE, Integer::max);

        System.out.println("Result: " + theMinValueUsingStaticReference);


        int theSumValueUsingStaticReference = IntStream.of(2,45,2,0,102,34,34,5,43,2)
                .reduce(0, Integer::sum);

        System.out.println("Result: " + theSumValueUsingStaticReference);

Output:

Result: 102
Result: 269

That would be it when it comes to basics of the reduce method.

Should you have any questions, don’t hesitate to reach me via linkedin, facebook, email or via comments.

If you want to know more visit: https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html – Oracle documentation website.

Let’s code!

Article featured image by:

“Reduce Key” by Got Credit is licensed under CC BY 2.0

Happy
Happy
0 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %
0 0 votes
Article Rating
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Majk
Majk
2 years ago

that’s a nice one!

1
0
Would love your thoughts, please comment.x
()
x