java中用stream+collectors.groupingby()可一行实现数据流分组,支持单字段、多条件、带聚合及动态分组,返回map或指定聚合结果,兼顾简洁性与类型安全。

Java 中用 Lambda 表达式做数据流分组查询,核心就是 Stream + Collectors.groupingBy(),一行代码就能把列表按条件拆成 Map,key 是分组依据,value 是该组所有元素的集合。
基础分组:按单个字段快速归类
最常见场景,比如按用户性别、订单日期、商品类型等字段分组:
- 写法简洁:直接传方法引用,如
User::getGender或 Lambda 表达式u -> u.getAge() / 10 * 10(按年龄段分组) - 结果是
Map<k list>></k>,例如Map<string list>></string>,遍历时可直接拿到每组数据 - 注意空值:若分组字段可能为 null,建议先 filter 或用
Objects.toString(u.getGender(), "未知")避免 NullPointerException
带聚合的分组:统计、求和、平均值一步到位
groupingBy 支持第二个参数传入下游收集器(downstream collector),无需额外遍历:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 统计每组数量:
Collectors.counting()→ 返回Map<k long></k> - 计算某字段平均值:
Collectors.averagingDouble(User::getSalary)→ 返回Map<k double></k> - 对某字段求和:
Collectors.summingInt(User::getAge)或summingDouble - 取每组最大/最小值:
Collectors.maxBy(Comparator.comparing(User::getSalary)),返回Optional<t></t>
多条件分组:组合多个字段作为 key
当需要“按部门+性别”或“按年份+月份”这类复合维度分组时:
- 构造 List 或自定义对象作 key,例如:
u -> Arrays.asList(u.getDept(), u.getGender()) - 更推荐用 record 或简单 Pair 类封装,语义清晰且可重用,避免 List 带来的泛型擦除和 equals 风险
- 也可嵌套 groupingBy:
groupingBy(User::getDept, groupingBy(User::getGender)),得到Map<dept map list>>></dept>
动态分组:运行时决定分组逻辑
如果分组字段不固定(比如前端传参控制按 age 还是 city 分),不能硬编码方法引用:
- 定义通用方法,参数为
Function<t k></t>,如<k> Map<k list>> groupBy(List<t> list, Function<t k> classifier)</t></t></k></k> - 调用时传入不同 Lambda:
groupBy(users, User::getCity)或groupBy(users, u -> u.getAge() >= 18 ? "adult" : "minor") - 避免反射或字符串解析,保持类型安全和 IDE 提示能力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










