在 Stream 流程的最後一步,collect() 方法配合 Collectors 工具類,將流元素匯聚為各種數據結構(List、Set、Map、字符串等)。本文深入剖析 Collector 的核心機制、常用靜態工廠方法,以及如何自定義 Collector 滿足複雜聚合需求。
Collector<T, A, R> 定義了三大核心操作:
ArrayList::new)List::add)Collections::unmodifiableList)| 分類 | 方法 | 返回類型 | 典型場景 |
|---|---|---|---|
| 集合收集 | toList() | List<T> | 最常用,保留順序與重複 |
| toSet() | Set<T> | 去重,無序 | |
| toCollection(Supplier) | Collection<T> | 指定具體集合類型(如 LinkedList) | |
| Map 收集 | toMap(keyMapper, valueMapper) | Map<K,V> | 鍵值非空、鍵唯一 |
| toMap(..., mergeFn) | Map<K,V> | 鍵衝突時合併值 | |
| toConcurrentMap(...) | ConcurrentMap | 併行環境下高性能 | |
| 字符串拼接 | joining() | String | 無分隔符直接拼接 |
| joining(delimiter) | String | 指定分隔符(如 CSV) | |
| 歸約統計 | counting() | Long | 元素計數 |
| summingInt/Long/Double(mapper) | Integer/Long/Double | 數值屬性求和 | |
| averagingInt/Long/Double(mapper) | Double | 計算平均值 | |
| summarizingInt/Long/Double(mapper) | IntSummaryStatistics 等 | 一次獲取 count、sum、min、max、average | |
| 分組與分區 | groupingBy(classifier) | Map<K, List<T>> | 單級分組 |
| groupingBy(classifier, downstream) | Map<K, D> | 多級分組或自定義下游收集 | |
| partitioningBy(predicate) | Map<Boolean, List<T>> | 二分分區(真/假) |
按部門再按性別分組,並統計每組平均薪資:
Map<String, Map<String, Double>> result = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDept,
Collectors.groupingBy(
Employee::getGender,
Collectors.averagingDouble(Employee::getSalary)
)
));
public static <T> Collector<T, ?, List<T>> distinctPreservingOrder() {
return Collector.of(
ArrayList::new, // supplier
(list, item) -> { if (!list.contains(item)) list.add(item); }, // accumulator
(list1, list2) -> { // combiner
list2.stream().filter(e -> !list1.contains(e)).forEach(list1::add);
return list1;
},
Collections::unmodifiableList // finisher
);
}
使用:list.stream().collect(distinctPreservingOrder())
toConcurrentMap、groupingByConcurrent 避免合併開銷。summarizingXxx 比多次遍歷高效得多。Collector 是 Stream 終端操作的核心,Collectors 提供了豐富的開箱即用工廠,覆蓋 90% 以上場景。掌握其組合規則(downstream collector)與自定義機制,能優雅解決複雜聚合需求。下一篇將探討 Comparator 在函數式排序中的新用法。