Writing a Custom Collector
The four functions behind every collector, and how to assemble your own when none of them fit.
Open this lesson in the learning hubKey points
- supplier makes the container, accumulator adds one element, combiner merges containers, finisher converts it.
Collector.of(...)builds one inline. The combiner is used only by parallel streams, but it must still be correct.- The three argument
collect(supplier, accumulator, combiner)skips the Collector object entirely for one off cases. collectingAndThenwraps a finishing step around a collector you already have, such as freezing a list.- Reach for a custom collector only when nesting the built in ones stops reading clearly. Most needs are already covered.
Example
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
List<String> names = List.of("ada", "grace", "alan");
// Four parts: supplier, accumulator, combiner, finisher.
Collector<String, StringJoiner, String> banner = Collector.of(
() -> new StringJoiner(" | ", "<", ">"),
(joiner, name) -> joiner.add(name.toUpperCase()),
StringJoiner::merge,
StringJoiner::toString);
System.out.println("custom : " + names.stream().collect(banner));
System.out.println("parallel : " + names.parallelStream().collect(banner));
// The same three functions inline, with no Collector object at all.
String inline = names.stream()
.collect(StringBuilder::new, (sb, n) -> sb.append(n).append(';'), StringBuilder::append)
.toString();
System.out.println("3-arg : " + inline);
// collectingAndThen wraps a finishing step around a collector you already have.
List<String> frozen = names.stream().collect(
Collectors.collectingAndThen(Collectors.toCollection(ArrayList::new), List::copyOf));
System.out.println("frozen : " + frozen);
try {
frozen.add("linus");
} catch (UnsupportedOperationException e) {
System.out.println("frozen : and it really is immutable");
}
}
}
Supplier, accumulator, combiner, finisher. Learn those four and every collector makes sense.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Streams course, and every lesson in it is listed on the Streams contents page.