collect是Stream API中用于累积元素的终端操作,可转换为集合、字符串或分组数据;常用toList、toSet转集合,joining拼接字符串,groupingBy按条件分组,partitioningBy分区,toMap转Map并处理键冲突,结合下游收集器实现复杂统计,支持并发与不可变集合。

在Java 8引入的Stream API中,collect 是一个非常强大的终端操作,用于将流中的元素累积成我们想要的结果形式,比如集合、字符串、分组数据等。它不像 forEach 那样只是遍历,而是真正“收集”结果,适用于大多数数据处理场景。
1. 基础用法:转为常见集合
最常用的 collect 操作是把流转换为 List、Set 或 Array。
// 转为List
List
立即学习“Java免费学习笔记(深入)”;
// 转为Set(去重)
Set
// 转为数组
String[] array = stream.toArray(String[]::new);
注意:toList 和 toSet 返回的是可变集合,若需不可变集合,建议使用 Collectors.toUnmodifiableList() 等方法(Java 10+)。
2. 使用joining合并字符串
当需要将流中的字符串拼接成一个整体时,joining 非常方便。
// 简单拼接
String names = people.stream().map(Person::getName).collect(Collectors.joining());
// 加分隔符
String joined = stream.collect(Collectors.joining(", "));
// 支持前缀和后缀
String result = stream.collect(Collectors.joining(", ", "[", "]"));
这比手动遍历拼接更简洁,也避免了多余的逗号处理。
3. 分组与分区:groupingBy 和 partitioningBy
实际开发中经常需要按条件分类数据,collect 提供了强大支持。
// 按性别分组
Map
.collect(Collectors.groupingBy(Person::getGender));
// 多级分组:先按部门,再按薪资等级
Map
.collect(Collectors.groupingBy(Person::getDept,
Collectors.groupingBy(p -> p.getSalary() > 8000 ? Level.HIGH : Level.LOW)));
// 分区:true/false 两组
Map
.collect(Collectors.partitioningBy(p -> p.getAge() >= 18));
4. 自定义收集:使用toMap和下游收集器
将流转换为Map时,需注意key重复问题。
// 正常转Map
Map
.collect(Collectors.toMap(Person::getId, p -> p));
// 处理重复key:保留第一个或合并
Map
.collect(Collectors.toMap(Person::getName, p -> p, (e1, e2) -> e1));
第三个参数是冲突解决策略。还可以结合下游收集器实现复杂结构:
// 按部门统计人数
Map
.collect(Collectors.groupingBy(Person::getDept, Collectors.counting()));
// 按部门计算平均薪资
Map
.collect(Collectors.groupingBy(Person::getDept, Collectors.averagingDouble(Person::getSalary)));
基本上就这些常用技巧。掌握 collect 的核心在于理解“收集器(Collector)”的组合逻辑。合理使用 groupingBy、mapping、reducing 等下游收集器,能让代码更清晰高效。不复杂但容易忽略细节,比如并发收集(toConcurrentMap)、不可变集合等,根据需求选择合适方式即可。










