Working with Stream Collectors
1. Collecting to List
| Method | Result |
|---|---|
Collectors.toList() | Mutable List (impl-specific) |
Collectors.toUnmodifiableList() | Immutable |
stream.toList() JAVA 16+ | Unmodifiable, allows null |
2. Collecting to Set
| Method | Result |
|---|---|
Collectors.toSet() | HashSet |
Collectors.toUnmodifiableSet() | Immutable |
Collectors.toCollection(TreeSet::new) | Custom Set impl |
3. Collecting to Map
Example: toMap
Map<Long, User> byId = users.stream()
.collect(Collectors.toMap(User::id, Function.identity()));
Map<String, Integer> sumByDept = employees.stream()
.collect(Collectors.toMap(
Employee::dept,
Employee::salary,
Integer::sum // merge function for duplicates
));
| Overload | Use |
|---|---|
| 2 args | Throws on duplicate keys |
| 3 args | Merge function for duplicates |
| 4 args | Custom map supplier |
4. Joining Strings
| Method | Result |
|---|---|
joining() | Concat with no delimiter |
joining(", ") | With delimiter |
joining(", ", "[", "]") | With prefix/suffix |
5. Grouping Elements
Example: groupingBy
Map<String, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::dept));
Map<String, Long> countByDept = employees.stream()
.collect(Collectors.groupingBy(Employee::dept, Collectors.counting()));
Map<String, Map<String, Long>> nested = employees.stream()
.collect(Collectors.groupingBy(Employee::dept,
Collectors.groupingBy(Employee::role, Collectors.counting())));
| Form | Detail |
|---|---|
groupingBy(classifier) | Classifier → List |
groupingBy(classifier, downstream) | Custom downstream collector |
groupingBy(classifier, mapFactory, downstream) | Custom map type |
6. Partitioning Elements
| Method | Result |
|---|---|
partitioningBy(predicate) | Map<Boolean, List<T>> |
| With downstream | partitioningBy(p, counting()) |
7. Counting Elements
| Method | Result |
|---|---|
Collectors.counting() | Long total |
stream.count() | long |
8. Finding Statistics
| Collector | Result |
|---|---|
summingInt/Long/Double(fn) | Sum |
averagingInt/Long/Double(fn) | Mean |
minBy(cmp) / maxBy(cmp) | Optional |
summarizingInt(fn) | IntSummaryStatistics (count, sum, min, max, avg) |
9. Reducing Elements
Example: reduce
int sum = nums.stream().reduce(0, Integer::sum);
Optional<Integer> max = nums.stream().reduce(Integer::max);
String concat = strs.stream().reduce("", (a, b) -> a + b);
| Form | Returns |
|---|---|
reduce(identity, op) | T |
reduce(op) | Optional<T> |
reduce(id, accumulator, combiner) | U (parallel-safe) |
10. Creating Custom Collectors
| Component | Detail |
|---|---|
| Supplier | New container |
| Accumulator | Add element to container |
| Combiner | Merge two containers (parallel) |
| Finisher | Transform container to result |
| Factory | Collector.of(supplier, accumulator, combiner, finisher) |
11. Collecting to Unmodifiable Collections
| Method | Result |
|---|---|
toUnmodifiableList() | Immutable list |
toUnmodifiableSet() | Immutable set |
toUnmodifiableMap(k, v) | Immutable map |
Warning: Unmodifiable collectors do NOT allow null elements/keys/values.
12. Using Downstream Collectors
Example: Downstream chaining
Map<String, Set<String>> emailsByDept = employees.stream()
.collect(Collectors.groupingBy(
Employee::dept,
Collectors.mapping(Employee::email, Collectors.toSet())
));
| Collector | Use |
|---|---|
mapping(fn, downstream) | Transform before collecting |
filtering(p, downstream) | Filter before collecting |
flatMapping(fn, downstream) | Flatten before collecting |
collectingAndThen(c, finisher) | Post-process result |