一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Java Stream API分组过滤:GroupingBy与Filter配合

时间:2026-06-20 08:28:55 编辑:袖梨 来源:一聚教程网

groupingBy本身不过滤,过滤需用filter()(分组前全局过滤)或filtering(分组后各组独立过滤);错误地在mapping中条件返回null会引发异常。

Java Stream API 中,groupingBy 本身不负责过滤,它只做分组;真正执行过滤逻辑的,是配合使用的下游 Collector(如 filtering)或前置的 filter() 操作。关键区别在于:前者在每个分组内部过滤,后者在分组前全局过滤——选错位置会导致结果偏差。

分组前过滤:用 stream.filter()

适用于“先筛再分”的场景,比如剔除无效数据后再按属性归类。

  • 操作时机:在 .collect(Collectors.groupingBy(...)) 之前调用
  • 影响范围:整个流,所有后续分组操作都基于已过滤的数据
  • 示例:只统计状态为 ACTIVE 的用户,并按部门分组

users.stream()
  .filter(u -> "ACTIVE".equals(u.getStatus()))
  .collect(Collectors.groupingBy(User::getDepartment));

分组后过滤:用 Collectors.filtering()

适用于“分组后按条件保留部分元素”,比如每个部门只保留薪资高于阈值的员工。

立即学习“Java免费学习笔记(深入)”;

  • 操作时机:作为 groupingBy 的下游 Collector 使用
  • 影响范围:每个分组独立过滤,不同组可应用不同规则
  • 要求:Java 9+(Collectors.filtering 是 Java 9 引入)

users.stream()
  .collect(Collectors.groupingBy(
    User::getDepartment,
    Collectors.filtering(u -> u.getSalary() > 15000, Collectors.toList())
  ));

避免常见错误:别在 mapping 里写 if 添加元素

有人试图在 mapping 中用条件判断来“选择性添加”,例如:

// ❌ 错误:有副作用,且逻辑混乱
Collectors.mapping(u -> {
  if (u.getAge() > 18) return u;
  else return null; // null 会引发异常
}, Collectors.toList())

这不仅破坏函数式风格,还可能抛出 NullPointerException。正确做法是把过滤逻辑交给 filtering 或前置 filter

进阶技巧:组合 filtering + mapping 精简结果

如果分组后只需提取某个字段(如 ID),而不是整个对象,可链式组合:

  • 先过滤符合条件的对象
  • 再映射为所需字段(如 getId()
  • 最后收集为 List

orders.stream()
  .collect(Collectors.groupingBy(
    Order::getStatus,
    Collectors.filtering(o -> o.getAmount() > 1000,
      Collectors.mapping(Order::getId, Collectors.toList())
    )
  ));

热门栏目