Java Stream reduce
last modified July 8, 2024
In this article we show to perform reduction operations on Java streams.
Java Stream is a sequence of elements from a source that supports aggregate operations. Streams do not store elements; the elements are computed on demand. Elements are consumed from data sources such as collections, arrays, or I/O resources.
Stream reduction
A reduction is a terminal operation that aggregates a stream into a
type or a primitive. The Java Stream API contains a set of predefined reduction
operations, such as average
, sum
, min
,
max
, and count
, which return one value by combining
the elements of a stream.
The reduce method
Stream.reduce
is a general-purpose method for generating our custom
reduction operations.
Optional<T> reduce(BinaryOperator<T> accumulator)
This method performs a reduction on the elements of this stream, using an
associative accumulation function. It returns an Optional
describing the reduced value, if any.
T reduce(T identity, BinaryOperator<T> accumulator)
This method takes two parameters: the identity and the accumulator. The identity
element is both the initial value of the reduction and the default result if
there are no elements in the stream. The accumulator function takes two
parameters: a partial result of the reduction and the next element of the
stream. It returns a new partial result. The Stream.reduce
method returns the result of the reduction.
Built-in reductions
The following example uses two predefined reduction operations.
import java.util.Arrays; void main() { int vals[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; int sum = Arrays.stream(vals).sum(); System.out.printf("The sum of values: %d%n", sum); long n = Arrays.stream(vals).count(); System.out.printf("The number of values: %d%n", n); }
We have an array of integers. We create a stream from the array with
Arrays.stream
and perform two reductions: sum
and count
.
The sum of values: 72 The number of values: 8
Java reduce Optional
The reduce
method with one parameter returns an
Optional
, which is a Java class for null safety.
import java.util.Arrays; import java.util.List; import java.util.Optional; void main() { List<Car> persons = Arrays.asList(new Car("Skoda", 18544), new Car("Volvo", 22344), new Car("Fiat", 23650), new Car("Renault", 19700)); Optional<Car> car = persons.stream().reduce((c1, c2) -> c1.price() > c2.price() ? c1 : c2); car.ifPresent(System.out::println); } record Car(String name, int price) { }
The example creates a list of car objects. We compute the most expensive car.
Optional<Car> car = persons.stream().reduce((c1, c2) -> c1.price() > c2.price() ? c1 : c2);
From the list, we create a stream; the accumulator of the reduce
method compares the prices of the cars and returns the more expensive one.
car.ifPresent(System.out::println);
If the returned reduction value is not null, we print it to the console.
Car{name=Fiat, price=23650}
The next example adds other use cases.
import java.util.stream.IntStream; void main() { IntStream.range(1, 10).reduce((x, y) -> x + y) .ifPresent(System.out::println); IntStream.range(1, 10).reduce(Integer::sum) .ifPresent(System.out::println); IntStream.range(1, 10).reduce(MyUtil::add2Ints) .ifPresent(System.out::println); } class MyUtil { static int add2Ints(int num1, int num2) { return num1 + num2; } }
We create three different accumulator functions to compute the sum of 1..10 values.
IntStream.range(1, 10).reduce((x, y) -> x + y) .ifPresent(System.out::println);
In the first case, we have a lambda expression doing the addition.
IntStream.range(1, 10).reduce(Integer::sum) .ifPresent(System.out::println);
The second case uses a built in Integer::sum
method.
IntStream.range(1, 10).reduce(MyUtil::add2Ints) .ifPresent(System.out::println);
Finally, we have a custom addition method.
Java reduce with identity
As we have already mentioned, the identity is both the initial value of the reduction and the default result if there are no elements in the stream.
import java.time.LocalDate; import java.time.chrono.IsoChronology; import java.util.ArrayList; import java.util.List; void main() { List<User> users = new ArrayList<>(); users.add(new User("Frank", LocalDate.of(1979, 11, 23))); users.add(new User("Peter", LocalDate.of(1985, 1, 18))); users.add(new User("Lucy", LocalDate.of(2002, 5, 14))); users.add(new User("Albert", LocalDate.of(1996, 8, 30))); users.add(new User("Frank", LocalDate.of(1967, 10, 6))); int maxAge = users.stream().mapToInt(User::getAge).reduce(0, Math::max); System.out.printf("The oldest user's age: %s%n", maxAge); } record User(String name, LocalDate dateOfBirth) { public int getAge() { return dateOfBirth.until(IsoChronology.INSTANCE.dateNow()).getYears(); } }
In the example, we create a list of users. The example calculates the age of the oldest user.
int maxAge = users.stream().mapToInt(User::getAge).reduce(0, Math::max);
From the list we create a Java stream. The stream is mapped to an
IntStream
with a mapToInt
method. Finally, the
reduce
method provides an identity value (0) and an accumulator;
the accumulator compares the age values and returns the bigger one.
Source
In this article we have have worked with Java Stream reduction operations.
Author
List all Java tutorials.