Let’s explore some advanced uses of reduce()
, including custom objects, parallel processing, and performance considerations.
1. Finding the Longest Word in a List
You can use reduce()
to find the longest string in a list.
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class LongestWord {
public static void main(String[] args) {
List words = Arrays.asList("Java", "Stream", "Reduction", "ParallelProcessing");
Optional longestWord = words.stream()
.reduce((word1, word2) -> word1.length() > word2.length() ? word1 : word2);
longestWord.ifPresent(word -> System.out.println("Longest Word: " + word));
}
}
Output:
Longest Word: ParallelProcessing
2. Finding the Most Frequent Character in a String
You can use reduce()
to count occurrences of each character and determine the most frequent one.
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class MostFrequentCharacter {
public static void main(String[] args) {
String input = "banana";
Map<Character, Long> frequencyMap = input.chars()
.mapToObj(c -> (char) c)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
// Finding the most frequent character
Character mostFrequent = frequencyMap.entrySet().stream()
.reduce((entry1, entry2) -> entry1.getValue() > entry2.getValue() ? entry1 : entry2)
.map(Map.Entry::getKey)
.orElse(null);
System.out.println("Most Frequent Character: " + mostFrequent);
}
}
Output:
Most Frequent Character: a
3. Summing a Specific Field in a List of Objects
In real-world applications, you often need to aggregate values from objects.
import java.util.Arrays;
import java.util.List;
class Product {
String name;
double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
public class ProductPriceSum {
public static void main(String[] args) {
List products = Arrays.asList(
new Product("Laptop", 1000.0),
new Product("Phone", 700.0),
new Product("Tablet", 400.0)
);
double totalPrice = products.stream()
.map(product -> product.price) // Extract prices
.reduce(0.0, Double::sum); // Sum them up
System.out.println("Total Price: $" + totalPrice);
}
}
Output:
Total Price: $2100.0
4. Using reduce()
with Parallel Streams for Large Data Sets
When using parallel streams, you must use the third variant of reduce()
that includes a combiner to efficiently merge results across multiple threads.
import java.util.Arrays;
import java.util.List;
public class ParallelReduce {
public static void main(String[] args) {
List numbers = Arrays.asList(2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.parallelStream()
.reduce(0, Integer::sum, Integer::sum);
System.out.println("Parallel Sum: " + sum);
}
}
Why the Combiner?
- The combiner is necessary when Java splits the work across multiple CPU cores.
- Each core computes a partial sum, and then the combiner merges the results efficiently.
Output:
Parallel Sum: 54
5. Finding the Employee with the Highest Salary
In applications, you might need to reduce a list of objects to find the one with the highest value.
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
class Employee {
String name;
double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
}
public class HighestSalary {
public static void main(String[] args) {
List employees = Arrays.asList(
new Employee("Alice", 70000),
new Employee("Bob", 85000),
new Employee("Charlie", 92000)
);
Optional highestPaid = employees.stream()
.reduce((e1, e2) -> e1.salary > e2.salary ? e1 : e2);
highestPaid.ifPresent(e -> System.out.println("Highest Paid Employee: " + e.name + " ($" + e.salary + ")"));
}
}
Output:
Highest Paid Employee: Charlie ($92000.0)
6. Combining Multiple Lists into One
The flatMap() method combined with reduce()
can merge multiple lists into one.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CombineLists {
public static void main(String[] args) {
List list1 = Arrays.asList("A", "B", "C");
List list2 = Arrays.asList("D", "E", "F");
List combined = Stream.of(list1, list2)
.flatMap(List::stream) // Flatten nested lists
.collect(Collectors.toList());
System.out.println("Combined List: " + combined);
}
}
Output:
Combined List: [A, B, C, D, E, F]
Key Takeaways for Advanced reduce()
Usage
- Use
reduce()
for aggregation, but prefer collectors (likeCollectors.summingInt()
) when available for better performance. - Parallel Streams require a combiner to merge partial results across multiple threads.
reduce()
is helpful for custom object comparisons, like finding max salary, min price, etc.- Be careful with mutable objects (like
StringBuilder
) insidereduce()
, as it’s not thread-safe in parallel execution.