All topics
streams
intermediate

Collectors

Build results from a stream — list, set, map, grouping, summary stats — using ready-made collector factories.

A Collector is the terminal operation that gathers the elements flowing out of a stream into a finished result — a list, a set, a map, a string, a grouping, or a summary statistic. The Collectors utility class supplies ready-made factories for the common cases, so most of the time you compose existing collectors rather than implement the interface yourself, and stream.collect(...) becomes the expressive endpoint of a pipeline.

A mailroom sorter — by ZIP code, then by street, then count letters per address. Each level uses a smaller sorter underneath.

Key Concepts

1
The everyday collectors are toList, toSet, and toMap, plus joining for concatenating strings with an optional delimiter, prefix, and suffix. The powerful ones are groupingBy and partitioningBy: groupingBy(Employee::getDepartment) produces a Map from each department to the list of its employees, and it accepts a downstream collector so you can, in one expression, group by department and then count, sum, average, or further group within each bucket — groupingBy(dept, counting()) or groupingBy(dept, mapping(Employee::getName, toList())). Numeric summarisers like summingInt, averagingDouble, and summarizingInt (which returns count, sum, min, max, and average together) cover aggregation. Under the hood a collector is defined by a supplier, an accumulator, a combiner, and an optional finisher, which is also what allows it to work correctly when the stream runs in parallel.
toListtoSettoMapjoininggroupingBy
2
The interview-relevant pitfalls cluster around toMap and grouping. toMap throws IllegalStateException if two elements produce the same key, so you must supply a merge function when collisions are possible. groupingBy returns a mutable HashMap with no ordering guarantee — pass a map supplier (e.g. TreeMap::new) if you need ordering. And remember that Collectors.toList historically returned an unspecified mutable list, so if you need immutability use toUnmodifiableList or Java 16's Stream.toList().
toMapIllegalStateExceptiongroupingByHashMapTreeMap::new