Collectors Class in Java

Naveen AnamaneniUpdated · 5 min read

The Collectors class in Java, in java.util.stream, is a utility class full of static methods that create collectors. A collector tells the terminal operation collect how to gather the elements of a stream into a result: a list, a set, a map, a string, a number or a group. In this lesson, you will learn the most useful collectors with examples. Grouping and partitioning are covered in detail in "groupingBy, partitioningBy, toMap and Joining".

Syntax

Syntax
import static java.util.stream.Collectors.*;
 
R result = stream.collect(someCollector());

Methods of Collectors

MethodDescription
toList()It collects into a List.
toSet()It collects into a Set.
toCollection(TreeSet::new)It collects into a collection of your choice.
toUnmodifiableList() / toUnmodifiableSet()It collects into an unmodifiable list or set.
toMap(keyFn, valueFn)It collects into a Map.
joining(", ")It joins strings with a separator.
counting()It counts the elements.
summingInt(f) / averagingInt(f)It totals or averages a number taken from each element.
minBy(c) / maxBy(c)It finds the smallest or largest by a comparator.
summarizingInt(f)It gives count, sum, min, average and max.
mapping(f, downstream)It transforms elements before another collector.
filtering(p, downstream)It filters elements before another collector (Java 9).
groupingBy(f)It groups elements into a map of lists.
partitioningBy(p)It splits elements into a true group and a false group.
teeing(c1, c2, merger)It runs two collectors and merges their results (Java 12).
collectingAndThen(c, f)It applies a final function to a collector's result.

Example: Collecting into Collections and Strings

Let's see an example of the basic collectors.

BasicCollectors.java▶ Try it
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
 
public class BasicCollectors {
    public static void main(String[] args) {
        List<String> names = List.of("Srihitha", "Navika", "Advitha", "Navika");
 
        List<String> list = names.stream().collect(Collectors.toList());
        Set<String> set = names.stream().collect(Collectors.toSet());
        TreeSet<String> sorted = names.stream()
            .collect(Collectors.toCollection(TreeSet::new));
        String joined = names.stream().distinct()
            .collect(Collectors.joining(", ", "[", "]"));
 
        System.out.println(list.size() + " in list, " + set.size() + " in set");
        System.out.println(sorted);
        System.out.println(joined);
    }
}
Output
4 in list, 3 in set
[Advitha, Navika, Srihitha]
[Srihitha, Navika, Advitha]

Explanation: toList keeps all four names, while toSet drops the duplicate Navika. toCollection(TreeSet::new) chooses the exact collection type. joining(", ", "[", "]") adds a separator, a prefix and a suffix.

Example: Counting, Summing and Averaging

NumberCollectors.java▶ Try it
import java.util.Comparator;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;
 
public class NumberCollectors {
    record Student(String name, int marks) { }
 
    public static void main(String[] args) {
        List<Student> students = List.of(
            new Student("Navika", 91), new Student("Srihitha", 78),
            new Student("Advitha", 85));
 
        long count = students.stream().collect(Collectors.counting());
        int total = students.stream()
            .collect(Collectors.summingInt(Student::marks));
        double average = students.stream()
            .collect(Collectors.averagingInt(Student::marks));
        String top = students.stream()
            .collect(Collectors.maxBy(Comparator.comparingInt(Student::marks)))
            .map(Student::name).orElse("none");
        IntSummaryStatistics stats = students.stream()
            .collect(Collectors.summarizingInt(Student::marks));
 
        System.out.println(count + " students, total " + total
            + ", average " + average + ", top " + top);
        System.out.println("min " + stats.getMin() + ", max " + stats.getMax());
    }
}
Output
3 students, total 254, average 84.66666666666667, top Navika
min 78, max 91

Explanation: These collectors produce single values. On their own, count(), mapToInt(...).sum() and max(...) are simpler; the collectors really shine as downstream collectors inside groupingBy, where they compute a value per group.

Example: teeing

Teeing.java▶ Try it
import java.util.List;
import java.util.stream.Collectors;
 
public class Teeing {
    public static void main(String[] args) {
        List<Integer> marks = List.of(91, 78, 85, 66);
        String range = marks.stream().collect(Collectors.teeing(
            Collectors.minBy(Integer::compare),
            Collectors.maxBy(Integer::compare),
            (min, max) -> min.get() + " to " + max.get()));
        System.out.println("Range: " + range);
    }
}
Output
Range: 66 to 91

Explanation: teeing sends every element to two collectors at once, here one for the minimum and one for the maximum, and then merges the two results with a function.

Common Mistakes

Assuming Collectors.toList() returns an unmodifiable list. It doesn't guarantee either way; stream.toList() is unmodifiable.

Using toSet() and expecting order. It's usually a HashSet; use toCollection(TreeSet::new) or LinkedHashSet::new.

Using collectors for simple totals. mapToInt(...).sum() is clearer than collect(summingInt(...)).

Interview Corner

What is the difference between stream.toList() and collect(Collectors.toList())?

stream.toList(), added in Java 16, always returns an unmodifiable list and allows null elements. collect(Collectors.toList()) returns a list whose type and mutability aren't guaranteed; in practice it is an ArrayList. Use toList() for read-only results, and Collectors.toCollection(ArrayList::new) when you need a list you can change.

Practice

  1. Easy: Collect a list of words into a comma-separated string of the words in upper case.
  2. Harder: Use teeing to compute both the count of passing marks and the count of failing marks in one pipeline, and print them as "3 passed, 1 failed".

Quick check: Collectors

4 questions
1Which collector joins strings?
2How do you collect into a TreeSet?
3Which collector runs two collectors and merges their results?
4Which terminal operation uses a collector?

Key Takeaways

Was this tutorial helpful?

Lesson 321 of 482