java stream api的groupingby配合counting()可简洁实现单层及多级分组计数,支持前置filter筛选、结果排序等扩展操作。

Java Stream API 的 groupingBy 是处理集合分组计数最常用也最直观的工具,它能一行代码替代传统循环+Map手动累加的繁琐逻辑,写法清晰、语义明确。
基础分组计数:用 counting() 最简实现
当只需统计每组元素数量时,Collectors.counting() 是首选。它不关心具体元素内容,只返回 Long 类型的计数值。
- 按字符串长度分组并计数:
Map<integer long> countByLength = strings.stream()<br> .collect(Collectors.groupingBy(String::length, Collectors.counting()));</integer>
- 按员工部门统计人数:
Map<string long> empCountByDept = employees.stream()<br> .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting()));</string>
多级嵌套分组:两层甚至三层结构轻松构建
真实业务常需“先按A分、再按B分”,比如部门→薪资区间、城市→区县、类别→品牌。这时可嵌套使用 groupingBy 作为下游收集器。
- 按部门分组,再在每个部门内按薪资区间(低于5000/5000–10000/高于10000)计数:
Map<string map long>> nested = employees.stream()<br> .collect(Collectors.groupingBy(Employee::getDepartment,<br> Collectors.groupingBy(e -> {<br> if (e.getSalary() else if (e.getSalary() else return "高于10000";<br> }, Collectors.counting())));</string> - 结果类型为
Map<string map long>></string>,可直接双层遍历或转成树形结构 DTO。
分组后带条件过滤再计数
不是所有数据都参与统计,常需先筛选再分组。把 filter 放在 stream() 链开头即可,不影响 groupingBy 逻辑。
- 只统计在职员工的部门人数:
Map<string long> activeCountByDept = employees.stream()<br> .filter(Employee::isOnboard)<br> .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting()));</string>
- 注意:不能把 filter 写在 collect 之后——Stream 只能消费一次,后续无法再调用 stream()。
按计数值排序输出:避免先 collect 再重排的低效写法
groupingBy 默认返回 HashMap,无序。若需按计数从高到低排列,应在 collect 后立即用 entrySet 流式排序,并重建有序 Map。
- 按出现频次降序,频次相同时按键升序(如字母顺序):
Map<string long> sorted = counts.entrySet().stream()<br> .sorted(Map.Entry.<string long>comparingByValue().reversed()<br> .thenComparing(Map.Entry::getKey))<br> .collect(Collectors.toMap(<br> Map.Entry::getKey,<br> Map.Entry::getValue,<br> (e1, e2) -> e1,<br> LinkedHashMap::new));</string></string>
- 关键点:最后一个参数
LinkedHashMap::new确保插入顺序保留,否则默认是 HashMap,排序无效。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











