1. 为什么需要groupingBy和reducing组合
在日常开发中,我们经常会遇到这样的需求:先按照某个字段分组,然后在每个分组内找出符合特定条件的记录。比如电商系统中按商品分类找出每个品类下价格最高的商品,或者人力资源系统中按部门筛选出绩效最好的员工。这类需求如果用传统方式实现,往往需要写多层循环和临时变量,代码既冗长又难以维护。
Java 8引入的Stream API彻底改变了这种局面。特别是Collectors.groupingBy和Collectors.reducing的组合使用,能够用声明式的方式优雅地解决这类问题。我曾在库存管理系统重构时,用这个组合替换了原来200多行的循环代码,最终只用了不到10行就实现了相同功能,而且可读性大大提升。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. groupingBy基础用法解析
2.1 最简单的分组操作
groupingBy是Stream中最常用的收集器之一,它的基础用法非常简单。假设我们有一批学生数据:
java复制List<Student> students = Arrays.asList(
new Student("Alice", "Math", 85),
new Student("Bob", "Math", 90),
new Student("Charlie", "Physics", 88)
);
如果我们要按学科分组,可以这样写:
java复制Map<String, List<Student>> bySubject = students.stream()
.collect(Collectors.groupingBy(Student::getSubject));
这个操作相当于SQL中的GROUP BY语句。但groupingBy的强大之处在于它支持更复杂的分组逻辑。
2.2 分组后的复杂操作
在实际项目中,我们往往需要在分组后对每个组进行进一步处理。比如计算每个学科的平均分:
java复制Map<String, Double> avgScoreBySubject = students.stream()
.collect(Collectors.groupingBy(
Student::getSubject,
Collectors.averagingInt(Student::getScore)
));
这里用到了groupingBy的重载方法,第二个参数是一个下游收集器(downstream collector),可以对分组后的元素做进一步归约。
3. reducing收集器深度剖析
3.1 reducing的核心原理
reducing收集器是Stream API中最灵活的归约操作之一。它的核心思想是通过一个二元操作(BinaryOpera
