partitioningBy 是 Java Stream API 中专为二元划分设计的收集器,仅按 true/false 一次性切分数据流,语义清晰、结果确定、无空指针风险;它接收 Predicate<T> 进行单次布尔判断,返回含 true/false 键的 Map,且空流时两键均映射空 List;支持下游收集器定制分区内容,性能优于双 filter。

Java Stream API 中的 partitioningBy 是专为二元划分设计的收集器,它不生成多组映射,只按 true/false 一次性切分数据流,语义清晰、结果确定、无空指针风险。
核心逻辑:布尔谓词驱动两路分流
partitioningBy 接收一个 Predicate<T>(如 user -> user.getAge() >= 18),对每个元素执行一次判断。结果只有两种可能:
- 返回 true → 元素进入 Map 的 true 键对应列表
- 返回 false → 元素进入 Map 的 false 键对应列表
与 groupingBy 不同,它不会因 null 返回值产生第三组,也不会因函数逻辑异常导致分组遗漏;即使流为空,map.get(true) 和 map.get(false) 也始终返回空 List,无需判空。
常见使用场景与写法
适用于所有非此即彼的业务判断,比如:
立即学习“Java免费学习笔记(深入)”;
- 用户状态:活跃 / 非活跃 →
Collectors.partitioningBy(User::isActive) - 数值属性:偶数 / 奇数 →
Collectors.partitioningBy(n -> n % 2 == 0) - 字符串特征:长度超限 / 未超限 →
Collectors.partitioningBy(s -> s.length() > 10) - 存在性检查:ID 在缓存中 / 不在缓存中 →
Collectors.partitioningBy(cache::containsKey)
增强用法:下游收集器定制分区内容
partitioningBy 支持传入第二个参数——下游收集器(downstream collector),用于对每个布尔分区内部做进一步聚合,例如:
- 统计每组数量:
partitioningBy(p -> p.getSalary() > 5000, Collectors.counting()) - 提取某字段并去重:
partitioningBy(u -> u.isActive(), mapping(User::getEmail, toSet())) - 按字母排序后再收集:
partitioningBy(s -> s.length() > 4, collectingAndThen(toList(), list -> list.stream().sorted().collect(toList())))
这种组合让分区不只是“分”,还能直接产出所需结构,避免后续额外遍历。
注意事项与避坑点
实际使用时需注意三点:
- 谓词必须空安全:若传入的 Predicate 内部访问了可能为 null 的字段(如 user.getName().length()),需提前判空,否则抛 NPE
- 不支持多级分组:partitioningBy 只能二分;若需按多个条件分多组(如按城市+状态),应改用 groupingBy
-
性能优于手写双 filter:相比分别调用
filter(cond).collect()两次,partitioningBy 只遍历流一次,效率更高且代码更简洁


















