Collectors and groupingBy

Useful Collectors

CollectorResult
toList(), toSet(), toCollection(TreeSet::new)collections
toMap(keyFn, valueFn, mergeFn)Map (merge function handles duplicate keys)
joining(", ", "[", "]")String
groupingBy(classifier, downstream)Map<K, List<T>> or with a downstream collector
partitioningBy(predicate)Map<Boolean, List<T>>
counting(), summingInt, averagingDoublenumbers (used as downstream)
mapping, filtering, flatMappingtransform inside a group
summarizingIntcount, sum, min, average, max in one go
teeing(c1, c2, merger) (Java 12)two collectors combined

Grouping Orders

Example

groupingBy returns a HashMap by default; pass TreeMap::new when you want sorted keys.

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List<Order> orders = List.of(
                new Order("Mumbai", "Electronics", 25000), new Order("Delhi", "Fashion", 3200),
                new Order("Mumbai", "Fashion", 1800), new Order("Pune", "Electronics", 15000),
                new Order("Delhi", "Electronics", 42000), new Order("Mumbai", "Grocery", 900));

        Map<String, Long> countByCity = orders.stream()
                .collect(Collectors.groupingBy(Order::city, TreeMap::new, Collectors.counting()));
        System.out.println("Orders per city: " + countByCity);

        Map<String, Integer> revenueByCategory = orders.stream()
                .collect(Collectors.groupingBy(Order::category, TreeMap::new, Collectors.summingInt(Order::amount)));
        System.out.println("Revenue per category: " + revenueByCategory);

        Map<String, List<String>> categoriesByCity = orders.stream()
                .collect(Collectors.groupingBy(Order::city, TreeMap::new,
                        Collectors.mapping(Order::category, Collectors.toList())));
        System.out.println("Categories per city: " + categoriesByCity);

        Map<Boolean, Long> bigOrders = orders.stream()
                .collect(Collectors.partitioningBy(o -> o.amount() >= 10000, Collectors.counting()));
        System.out.println("Big vs small: " + bigOrders);

        IntSummaryStatistics stats = orders.stream().collect(Collectors.summarizingInt(Order::amount));
        System.out.println("Stats: min=" + stats.getMin() + " max=" + stats.getMax() + " avg=" + stats.getAverage());
    }
}

record Order(String city, String category, int amount) {}

Output

Orders per city: {Delhi=2, Mumbai=3, Pune=1}
Revenue per category: {Electronics=82000, Fashion=5000, Grocery=900}
Categories per city: {Delhi=[Fashion, Electronics], Mumbai=[Electronics, Fashion, Grocery], Pune=[Electronics]}
Big vs small: {false=3, true=3}
Stats: min=900 max=42000 avg=14650.0

toMap and joining

Example

toMap throws IllegalStateException on duplicate keys unless you pass a merge function.

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List<String> words = List.of("java", "kotlin", "jdbc", "spring", "kafka");

        Map<Character, String> byFirstLetter = words.stream()
                .collect(Collectors.toMap(w -> w.charAt(0), w -> w, (a, b) -> a + "|" + b, TreeMap::new));
        System.out.println(byFirstLetter);

        String csv = words.stream().map(String::toUpperCase).collect(Collectors.joining(", ", "[", "]"));
        System.out.println(csv);

        double avgLen = words.stream().collect(Collectors.averagingInt(String::length));
        System.out.println("Average length: " + avgLen);
    }
}

Output

{j=java|jdbc, k=kotlin|kafka, s=spring}
[JAVA, KOTLIN, JDBC, SPRING, KAFKA]
Average length: 5.0