reduce
TL;DR
reduce()is a terminal operation used to combine all elements of a stream into a single result (e.g., sum, max, min).- It takes an initial identity value and a
BinaryOperator(an accumulator). - The operation repeatedly applies the accumulator to combine the current result with the next element in the stream.
Concept
Reduction operations take a sequence of input elements and combine them into a single summary result.
A classic example is summing an array of numbers. You start with a total of 0 (the Identity). You take the first number and add it to the total (the Accumulator). You take the next number and add it to the total, until the stream is empty.
reduce comes in several overloaded forms:
reduce(BinaryOperator accumulator): Returns anOptional(in case the stream was empty).reduce(T identity, BinaryOperator accumulator): ReturnsT(uses the identity if the stream is empty).
Examples
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 1. reduce with Identity
// Starts with 0.
// 0+1=1 -> 1+2=3 -> 3+3=6 -> 6+4=10 -> 10+5=15
int sum = numbers.stream()
.reduce(0, (total, n) -> total + n);
System.out.println("Sum: " + sum); // 15
// Shorthand using Method Reference
int sumShorthand = numbers.stream().reduce(0, Integer::sum);
// 2. reduce without Identity (returns Optional)
// Useful for finding Max/Min where a default value like 0 doesn't make sense.
Optional<Integer> max = numbers.stream()
.reduce((currentMax, n) -> n > currentMax ? n : currentMax);
max.ifPresent(m -> System.out.println("Max: " + m)); // 5
// String concatenation example
List<String> letters = Arrays.asList("a", "b", "c");
String combined = letters.stream().reduce("", String::concat);
System.out.println(combined); // "abc"
}
}
Interview Questions
Q: What happens if you use reduce on an empty stream without an identity value?
A: If you call stream.reduce(accumulator) on an empty stream, it has no data to operate on and no starting value to fall back to. Therefore, it returns an empty Optional. If you use the version with an identity, stream.reduce(identity, accumulator), it simply returns the identity value.
Q: Why is using reduce for String concatenation considered bad practice?
A: Because String is immutable in Java, reduce("", String::concat) creates a brand new String object in memory for every single element in the stream. If you have 10,000 elements, it creates 10,000 discarded Strings, destroying performance and triggering garbage collection. Instead, you should use .collect(Collectors.joining()), which uses a highly efficient StringBuilder under the hood.