Java Stream合并流后收集到自定义集合需用Collector.of()构建自定义收集器,含supplier、accumulator、combiner三要素,可封装为静态方法复用,并能与groupingBy等下游收集器嵌套使用。

Java Stream API 合并流后,想收集到自定义集合(比如非标准的 List 实现、特定结构的容器或带业务逻辑的包装类),不能只靠 Collectors.toList() 这类内置收集器。关键在于用 Collector 接口自定义收集行为,把合并后的元素按需装入目标结构。
用 Collector.of() 快速构建轻量级自定义收集器
不需要写完整实现类,Collector.of() 提供简洁入口,适合多数场景:
-
supplier:提供空的自定义集合实例,如
() -> new LinkedHashSet<>()或MyCustomList::new -
accumulator:定义如何往集合里加元素,如
(list, item) -> list.add(item) -
combiner:多线程并行流时合并两个部分结果,如
(list1, list2) -> { list1.addAll(list2); return list1; } - finisher(可选):若需对最终集合做加工(如排序、截断),在此处理;若直接返回即可省略
示例:合并两个流,收集到 TreeSet 并保持自然排序
List<String> result = Stream.concat(stream1, stream2)
.collect(Collector.of(
TreeSet::new,
(set, s) -> set.add(s),
(set1, set2) -> { set1.addAll(set2); return set1; }
));
合并多个流再进自定义集合
当源头不止两个流(比如 List<List<T>> 或 Stream<Stream<T>>),先用 flatMap 扁平化,再用自定义收集器:
立即学习“Java免费学习笔记(深入)”;
- 多个 List 合并:用
Stream.of(list1, list2, list3).flatMap(List::stream)得到统一流 - 嵌套流合并:用
Stream.of(stream1, stream2, stream3).flatMap(Function.identity()) - 之后统一调用
.collect(你的自定义Collector)
注意:若自定义集合本身不支持并发(如多数非线程安全集合),避免在并行流中使用 CONCURRENT 特性,或显式指定 Collector.Characteristics.IDENTITY_FINISH 等安全特性。
封装成可复用的静态收集器
把常用逻辑封装成静态方法,提升可读性和复用性:
- 例如定义
Collectors.toImmutableList()类似物:toUnmodifiableList() - 或业务专用收集器:
Collectors.toUserGroupMap(),内部自动按角色分组+去重+排序 - 这样合并代码变成:
Stream.concat(a, b).collect(MyCollectors.toSortedUniqueSet())
这类封装本质仍是 Collector.of() 的包装,但隐藏了细节,让主逻辑聚焦业务。
与 groupingBy / mapping 等下游收集器配合
如果合并后还需分组、映射等聚合操作,自定义收集器可作为下游收集器嵌套使用:
- 例如:先按部门分组,每组内收集为自定义缓存列表
CacheableList - 写法:
stream.collect(groupingBy(User::getDept, collectingAndThen(toList(), CacheableList::new))) - 或更彻底:
groupingBy(User::getDept, Collector.of(CacheableList::new, ...))
这种组合方式避免手动遍历分组 Map,保持函数式风格连贯性。


















