Collector.of 是 Java 8 提供的自定义 Collector 工厂方法,支持线程安全、可合并的聚合操作;适用于加权平均、不可变容器构建、条件分组取前 N 等复杂场景,需显式定义 Supplier、BiConsumer、BinaryOperator、Function 及 Characteristics。

Collector.of 是 Java 8 Stream API 中用于自定义 Collector 的核心静态工厂方法,它让你能精准控制并行流中变量的收集逻辑——尤其适合需要高效、线程安全、可合并(combinable)的聚合场景。
为什么用 Collector.of 而不是 Collectors.toList()?
默认收集器(如 toList()、toSet())简单通用,但无法满足复杂聚合需求。比如:统计带权重的平均值、构建不可变容器、按条件分组后只取前 N 个、或在收集过程中做实时校验。
而 Collector.of 允许你显式定义:
-
Supplier:创建中间结果容器(如
new ConcurrentHashMap()或new StringBuilder()) - BiConsumer:如何把单个元素“累积”进容器(add / append / update)
- BinaryOperator:如何把两个并行分支的中间结果“合并”(必须满足结合律,否则并行结果不一致)
- Function(可选):最终转换(如把 map 转为不可变副本)
- Characteristics(可选):标记是否支持并发(CONCURRENT)、无序(UNORDERED)、不可变(IDENTITY_FINISH)等,直接影响并行性能
写一个线程安全的计数+求和收集器
目标:一次遍历,同时统计元素个数和总和,且支持并行流高效合并。
Collector<Integer, long[], Double> countAndSum = Collector.of(
() -> new long[]{0L, 0L}, // [count, sum],用 long[] 避免对象开销
(arr, n) -> {
arr[0]++;
arr[1] += n;
},
(a, b) -> {
a[0] += b[0];
a[1] += b[1];
return a;
},
arr -> (double) arr[1] / Math.max(1, arr[0]), // 平均值
Collector.Characteristics.CONCURRENT
);
关键点:
- 用原始数组代替对象封装,减少 GC 压力
-
CONCURRENT特性让并行流直接使用同一个容器(无需拆分再合并),性能更高 - 合并函数(third arg)就地修改左操作数,避免频繁新建数组
避免常见陷阱
不声明 CONCURRENT 却用全局容器(如 static HashMap)→ 并行时竞态失败
合并函数不满足结合律(如用 LinkedList.addFirst)→ 并行结果随机
finisher 返回原容器(未深拷贝)→ 外部误改破坏后续使用
- 始终优先用无状态、不可变或线程安全的中间容器(
ConcurrentHashMap、LongAdder、数组) - 测试务必覆盖
parallelStream().collect(...)场景,不能只测串行 - 若 finisher 只是类型转换(如
list -> List.copyOf(list)),加IDENTITY_FINISH可跳过这步
进阶:组合多个 Collector 实现分层聚合
比如:按城市分组 → 每组内再按年龄段统计人数。可用 Collector.of 嵌套构造:
Collector<Person, ?, Map<String, Map<String, Long>>> cityAgeGroup = Collector.of(
HashMap::new,
(map, p) -> map.computeIfAbsent(p.city(), k -> new HashMap<>())
.merge(ageRange(p.age()), 1L, Long::sum),
(m1, m2) -> {
m2.forEach((city, ageMap) ->
m1.merge(city, ageMap, (a, b) -> {
b.forEach((range, cnt) -> a.merge(range, cnt, Long::sum));
return a;
})
);
return m1;
}
);
这种结构清晰、可读性强,且比多次 collect + 手动嵌套循环更易维护和并行化。

















