Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Streams & Functional Programming

Lambdas & Functional Interfaces

  • Lambda Expressions
  • Method References

Streams API

  • Streams API
  • Collectors and groupingBy
  • Optional
Chaturmind
← Java Streams & Functional Programming

Lambdas & Functional Interfaces

  • Lambda Expressions
  • Method References

Streams API

  • Streams API
  • Collectors and groupingBy
  • Optional
HomeLearnJavaJava Streams & FunctionalStreams API
✓ FreeIntermediate· 12 min read

Collectors

Use toList, groupingBy, partitioningBy, joining, counting, and custom collectors to aggregate stream data.

Published February 21, 2025


Collectors

Collectors is a factory class providing implementations of Collector — the terminal operation that reduces a stream into a result container. Beyond simple toList(), collectors unlock grouping, partitioning, statistics, and string joining.

Basic Collectors

List<String> names = stream.collect(Collectors.toList());
Set<String>  nameSet = stream.collect(Collectors.toSet());
String csv = stream.collect(Collectors.joining(", "));
String delimited = stream.collect(Collectors.joining(", ", "[", "]"));
long count = stream.collect(Collectors.counting());

groupingBy — the most powerful collector

List<Person> people = ...;

// Group by one field
Map<String, List<Person>> byCity =
    people.stream().collect(Collectors.groupingBy(Person::getCity));

// Group and count (downstream collector)
Map<String, Long> countByCity =
    people.stream().collect(
        Collectors.groupingBy(Person::getCity, Collectors.counting()));

// Group and collect to specific collection type
Map<String, Set<String>> emailsByCity =
    people.stream().collect(
        Collectors.groupingBy(Person::getCity,
            Collectors.mapping(Person::getEmail, Collectors.toSet())));

// Multi-level grouping
Map<String, Map<String, List<Person>>> byCityThenGender =
    people.stream().collect(
        Collectors.groupingBy(Person::getCity,
            Collectors.groupingBy(Person::getGender)));

partitioningBy — split into true/false

// Split into adults and minors
Map<Boolean, List<Person>> partitioned =
    people.stream().collect(
        Collectors.partitioningBy(p -> p.getAge() >= 18));

List<Person> adults = partitioned.get(true);
List<Person> minors = partitioned.get(false);

Statistics and Summaries

// Statistics in one pass
IntSummaryStatistics stats = people.stream()
    .collect(Collectors.summarizingInt(Person::getAge));

stats.getCount();   // 100
stats.getSum();     // 3500
stats.getMin();     // 18
stats.getMax();     // 75
stats.getAverage(); // 35.0

// Simpler aggregations
Optional<Integer> max = people.stream()
    .collect(Collectors.maxBy(Comparator.comparing(Person::getAge)));

Double average = people.stream()
    .collect(Collectors.averagingInt(Person::getAge));

Integer sum = people.stream()
    .collect(Collectors.summingInt(Person::getSalary));

toMap — convert to a Map

// toMap(keyMapper, valueMapper)
Map<String, Person> byEmail =
    people.stream().collect(
        Collectors.toMap(Person::getEmail, p -> p));

// With merge function for duplicate keys
Map<String, String> cityToFirstName =
    people.stream().collect(
        Collectors.toMap(
            Person::getCity,
            Person::getName,
            (existing, replacement) -> existing // keep first
        ));

teeing — collect into two collectors at once (Java 12+)

record Summary(long count, double average) {}

Summary summary = people.stream().collect(
    Collectors.teeing(
        Collectors.counting(),
        Collectors.averagingInt(Person::getAge),
        Summary::new
    )
);

Unmodifiable Collections (Java 10+)

List<String> immutable = stream.collect(Collectors.toUnmodifiableList());
Set<String>  immutableSet = stream.collect(Collectors.toUnmodifiableSet());

Interview Tips

  1. groupingBy with a downstream collector is a common interview question — know how to group and then aggregate (count, sum, join).
  2. Know partitioningBy returns exactly a Map<Boolean, List<T>> — the map always has both true and false keys.
  3. Collectors.toList() returns a mutable list; Stream.toList() (Java 16+) returns an unmodifiable list — they differ in mutability.

Previous

Streams API

Next

Optional

AI Tutor

Lesson: Collectors

Quick actions

AI responses can be inaccurate. Verify critical information.