After filtering and transforming stream elements, you typically need to gather results into a collection or compute aggregate values. The collect operation provides flexible, efficient ways to accumulate stream results.

Basic Collectors

The collect operation is a terminal operation that uses a Collector to gather elements. The Collectors utility class provides common collectors for lists, sets, and maps.

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

public class Basic {
    public static void main(String[] args) {
        List<String> words = ;

        List<String> list = words.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("list: " + list);

        Set<String> set = words.stream().collect(Collectors.toCollection(LinkedHashSet::new));
        System.out.println("set: " + set);

        List<String> items = Arrays.asList("a", "bb", "ccc");
        Map<String, Integer> lengths = items.stream()
                .collect(Collectors.toMap(s -> s, String::length, (a, b) -> a, LinkedHashMap::new));
        System.out.println("lengths: " + lengths);

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

public class Basic {
    public static void main(String[] args) {
        List<String> words = ;

        List<String> list = words.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("list: " + list);

        Set<String> set = words.stream().collect(Collectors.toCollection(LinkedHashSet::new));
        System.out.println("set: " + set);

        List<String> items = Arrays.asList("a", "bb", "ccc");
        Map<String, Integer> lengths = items.stream()
                .collect(Collectors.toMap(s -> s, String::length, (a, b) -> a, LinkedHashMap::new));
        System.out.println("lengths: " + lengths);

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

public class Basic {
    public static void main(String[] args) {
        List<String> words = ;

        List<String> list = words.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("list: " + list);

        Set<String> set = words.stream().collect(Collectors.toCollection(LinkedHashSet::new));
        System.out.println("set: " + set);

        List<String> items = Arrays.asList("a", "bb", "ccc");
        Map<String, Integer> lengths = items.stream()
                .collect(Collectors.toMap(s -> s, String::length, (a, b) -> a, LinkedHashMap::new));
        System.out.println("lengths: " + lengths);

    }
}
collector A recipe for how to accumulate stream elements into a result container, such as a list, set, map, or custom structure.
toMap A collector that builds a Map from stream elements using key and value mapper functions.

Joining Strings

The joining collector concatenates strings with optional delimiter, prefix, and suffix.

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

public class Joining {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry");
        String delimiter = ;

        String concat = words.stream().collect(Collectors.joining());
        System.out.println("concat: " + concat);

        String csv = words.stream().collect(Collectors.joining(delimiter));
        System.out.println("csv: " + csv);

        String bracketed = words.stream()
                .collect(Collectors.joining(", ", "[", "]"));
        System.out.println("bracketed: " + bracketed);

        List<Integer> nums = Arrays.asList(1, 2, 3);
        String result = nums.stream()
                .map(n -> "num" + n)
                .collect(Collectors.joining(" | "));
        System.out.println("result: " + result);

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

public class Joining {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry");
        String delimiter = ;

        String concat = words.stream().collect(Collectors.joining());
        System.out.println("concat: " + concat);

        String csv = words.stream().collect(Collectors.joining(delimiter));
        System.out.println("csv: " + csv);

        String bracketed = words.stream()
                .collect(Collectors.joining(", ", "[", "]"));
        System.out.println("bracketed: " + bracketed);

        List<Integer> nums = Arrays.asList(1, 2, 3);
        String result = nums.stream()
                .map(n -> "num" + n)
                .collect(Collectors.joining(" | "));
        System.out.println("result: " + result);

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

public class Joining {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry");
        String delimiter = ;

        String concat = words.stream().collect(Collectors.joining());
        System.out.println("concat: " + concat);

        String csv = words.stream().collect(Collectors.joining(delimiter));
        System.out.println("csv: " + csv);

        String bracketed = words.stream()
                .collect(Collectors.joining(", ", "[", "]"));
        System.out.println("bracketed: " + bracketed);

        List<Integer> nums = Arrays.asList(1, 2, 3);
        String result = nums.stream()
                .map(n -> "num" + n)
                .collect(Collectors.joining(" | "));
        System.out.println("result: " + result);

    }
}

Grouping

Group elements by a classification function into a Map<K, List<T>>.

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

public class Grouping {
    public static void main(String[] args) {
        List<String> words = ;

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

        Map<Integer, List<String>> byLength = words.stream()
                .collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.toList()));
        System.out.println("byLength: " + byLength);

        Map<Character, Long> counts = words.stream()
                .collect(Collectors.groupingBy(w -> w.charAt(0), TreeMap::new, Collectors.counting()));
        System.out.println("counts: " + counts);

        Map<Character, Double> avgLengths = words.stream()
                .collect(Collectors.groupingBy(
                        w -> w.charAt(0),
                        TreeMap::new,
                        Collectors.averagingInt(String::length)
                ));
        System.out.println("avgLengths: " + avgLengths);

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

public class Grouping {
    public static void main(String[] args) {
        List<String> words = ;

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

        Map<Integer, List<String>> byLength = words.stream()
                .collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.toList()));
        System.out.println("byLength: " + byLength);

        Map<Character, Long> counts = words.stream()
                .collect(Collectors.groupingBy(w -> w.charAt(0), TreeMap::new, Collectors.counting()));
        System.out.println("counts: " + counts);

        Map<Character, Double> avgLengths = words.stream()
                .collect(Collectors.groupingBy(
                        w -> w.charAt(0),
                        TreeMap::new,
                        Collectors.averagingInt(String::length)
                ));
        System.out.println("avgLengths: " + avgLengths);

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

public class Grouping {
    public static void main(String[] args) {
        List<String> words = ;

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

        Map<Integer, List<String>> byLength = words.stream()
                .collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.toList()));
        System.out.println("byLength: " + byLength);

        Map<Character, Long> counts = words.stream()
                .collect(Collectors.groupingBy(w -> w.charAt(0), TreeMap::new, Collectors.counting()));
        System.out.println("counts: " + counts);

        Map<Character, Double> avgLengths = words.stream()
                .collect(Collectors.groupingBy(
                        w -> w.charAt(0),
                        TreeMap::new,
                        Collectors.averagingInt(String::length)
                ));
        System.out.println("avgLengths: " + avgLengths);

    }
}
groupingBy A collector that partitions elements into a Map where keys are computed by a classifier function.

Partitioning

Partition elements into two groups based on a predicate: Map<Boolean, List<T>>.

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

public class Partitioning {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        int minWordLength = ;

        Map<Boolean, List<Integer>> partitioned = nums.stream()
                .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println("evens: " + partitioned.get(true));
        System.out.println("odds: " + partitioned.get(false));

        List<String> words = Arrays.asList("a", "bb", "ccc", "d", "eeee");
        Map<Boolean, List<String>> longWords = words.stream()
                .collect(Collectors.partitioningBy(s -> s.length() >= minWordLength));
        System.out.println("longWords: " + longWords);

        Map<Boolean, Long> counts = nums.stream()
                .collect(Collectors.partitioningBy(n -> n > 5, Collectors.counting()));
        System.out.println("counts: " + counts);

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

public class Partitioning {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        int minWordLength = ;

        Map<Boolean, List<Integer>> partitioned = nums.stream()
                .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println("evens: " + partitioned.get(true));
        System.out.println("odds: " + partitioned.get(false));

        List<String> words = Arrays.asList("a", "bb", "ccc", "d", "eeee");
        Map<Boolean, List<String>> longWords = words.stream()
                .collect(Collectors.partitioningBy(s -> s.length() >= minWordLength));
        System.out.println("longWords: " + longWords);

        Map<Boolean, Long> counts = nums.stream()
                .collect(Collectors.partitioningBy(n -> n > 5, Collectors.counting()));
        System.out.println("counts: " + counts);

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

public class Partitioning {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        int minWordLength = ;

        Map<Boolean, List<Integer>> partitioned = nums.stream()
                .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println("evens: " + partitioned.get(true));
        System.out.println("odds: " + partitioned.get(false));

        List<String> words = Arrays.asList("a", "bb", "ccc", "d", "eeee");
        Map<Boolean, List<String>> longWords = words.stream()
                .collect(Collectors.partitioningBy(s -> s.length() >= minWordLength));
        System.out.println("longWords: " + longWords);

        Map<Boolean, Long> counts = nums.stream()
                .collect(Collectors.partitioningBy(n -> n > 5, Collectors.counting()));
        System.out.println("counts: " + counts);

    }
}

Aggregations with Downstream Collectors

Combine grouping with downstream collectors for powerful aggregations.

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

public class Aggregations {
    public static void main(String[] args) {
        List<Integer> nums = ;

        long count = nums.stream().collect(Collectors.counting());
        System.out.println("count: " + count);

        int sum = nums.stream().collect(Collectors.summingInt(Integer::intValue));
        System.out.println("sum: " + sum);

        double avg = nums.stream().collect(Collectors.averagingDouble(Integer::doubleValue));
        System.out.println("avg: " + avg);

        IntSummaryStatistics stats = nums.stream().collect(Collectors.summarizingInt(Integer::intValue));
        System.out.println("stats: count=" + stats.getCount() + ", sum=" + stats.getSum() +
                ", min=" + stats.getMin() + ", max=" + stats.getMax() + ", avg=" + stats.getAverage());

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

public class Aggregations {
    public static void main(String[] args) {
        List<Integer> nums = ;

        long count = nums.stream().collect(Collectors.counting());
        System.out.println("count: " + count);

        int sum = nums.stream().collect(Collectors.summingInt(Integer::intValue));
        System.out.println("sum: " + sum);

        double avg = nums.stream().collect(Collectors.averagingDouble(Integer::doubleValue));
        System.out.println("avg: " + avg);

        IntSummaryStatistics stats = nums.stream().collect(Collectors.summarizingInt(Integer::intValue));
        System.out.println("stats: count=" + stats.getCount() + ", sum=" + stats.getSum() +
                ", min=" + stats.getMin() + ", max=" + stats.getMax() + ", avg=" + stats.getAverage());

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

public class Aggregations {
    public static void main(String[] args) {
        List<Integer> nums = ;

        long count = nums.stream().collect(Collectors.counting());
        System.out.println("count: " + count);

        int sum = nums.stream().collect(Collectors.summingInt(Integer::intValue));
        System.out.println("sum: " + sum);

        double avg = nums.stream().collect(Collectors.averagingDouble(Integer::doubleValue));
        System.out.println("avg: " + avg);

        IntSummaryStatistics stats = nums.stream().collect(Collectors.summarizingInt(Integer::intValue));
        System.out.println("stats: count=" + stats.getCount() + ", sum=" + stats.getSum() +
                ", min=" + stats.getMin() + ", max=" + stats.getMax() + ", avg=" + stats.getAverage());

    }
}
downstream A secondary collector applied to grouped elements, enabling multi-level aggregation.

Exercise: Practical.java

Collect transaction data grouped by category with totals and counts