5 Advanced reduce() Examples in Java Streams API

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 (like Collectors.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) inside reduce(), as it’s not thread-safe in parallel execution.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *