实现自定义Collector需提供supplier、accumulator、combiner、finisher四组件并声明characteristics:1.据目标选中间容器;2.用Collector.of()组装四函数;3.合理设置CONCURRENT、UNORDERED、IDENTITY_FINISH等特征;4.分别验证串行与并行流行为。

要实现一个自定义的 Collector,核心是提供四个关键组件:supplier(容器创建)、accumulator(元素累积)、combiner(并行合并)、finisher(最终转换),并声明其特征(characteristics)。
1. 明确收集目标与中间容器
先想清楚你要收集成什么结果,比如去重后的字符串拼接、分组统计、构建自定义对象等。这决定了 supplier 返回的“中间容器”类型。例如,若目标是拼接不重复的字符串,中间容器可用 LinkedHashSet<String> 保证顺序和去重;若要统计频次,可用 HashMap<T, Integer>。
- 容器不必是最终返回类型,只是便于累积过程操作
- 尽量选线程安全或适合单线程累积的类型;并行时由 combiner 负责合并,不要在 accumulator 中做跨线程操作
2. 实现四个核心函数
通过 Collector.of() 静态工厂方法组装,依次传入:
-
supplier:如
() -> new LinkedHashSet<>(),每次新建空容器 -
accumulator:如
(set, item) -> set.add(item),将流中每个元素加入容器 -
combiner:如
(set1, set2) -> { set1.addAll(set2); return set1; },合并两个中间容器(仅并行流需要) -
finisher:如
set -> String.join(",", set),将最终容器转为目标结果
注意:如果 finisher 是恒等函数(如 Function.identity()),可省略,此时 collector 直接返回中间容器。
立即学习“Java免费学习笔记(深入)”;
3. 正确声明 Characteristics(特征)
最后一个参数是 Set<Collector.Characteristics>,常见选项有:
-
CONCURRENT:表示 accumulator 可以多线程安全调用(如使用ConcurrentHashMap),此时 supplier 必须返回同一共享实例(但通常不推荐,易出错) -
UNORDERED:表示收集结果不依赖元素原始顺序(如统计总数、求最大值),启用后可提升并行性能 -
IDENTITY_FINISH:表示 finisher 是恒等操作,可跳过转换步骤
多数自定义 collector 不设 CONCURRENT,而是依赖 combiner 合并 —— 这更安全、更通用。
4. 使用与验证
直接在 stream 后调用 collect(yourCollector) 即可。建议同时测试串行和并行流:
- 串行流验证逻辑是否正确(如去重、拼接顺序)
- 并行流验证 combiner 是否幂等且无副作用(例如不能写
list1.addAll(list2); return list2;,会导致数据丢失) - 检查是否意外修改了原始数据(如在 accumulator 中修改入参对象)
不复杂但容易忽略细节。


















