partitioningBy() 仅支持布尔分区,键固定为 true/false;需防 null 用 Objects.nonNull() 或预过滤;改键名应换用 groupingBy();顺序敏感时传 LinkedHashMap::new;并行安全但 predicate 勿改共享状态。

partitioningBy() 的基本用法和分区逻辑
Collectors.partitioningBy() 本质是做布尔分类:它只接受一个 Predicate,返回一个 Map<boolean list>></boolean>,其中键只有 true 和 false 两个值。它不支持多级分组或自定义键名,这点和 groupingBy() 有根本区别。
对学生按“是否及格”分组,就是判断 score >= 60(假设及格线为 60),这个判断直接传给 partitioningBy() 即可:
Map<Boolean, List<Student>> partitioned = students.stream()
.collect(Collectors.partitioningBy(s -> s.getScore() >= 60));
结果中:partitioned.get(true) 是及格学生列表,partitioned.get(false) 是不及格学生列表。
如何避免空指针和数据异常
如果 Student 的 score 是 Integer 类型(可能为 null),直接调用 getScore() >= 60 会触发 NullPointerException。
- 用
Objects.nonNull()先判空:s -> Objects.nonNull(s.getScore()) && s.getScore() >= 60 - 或统一用
int类型字段(推荐),避免包装类空值问题 - 若成绩字段来自外部 API 或数据库,建议在流处理前先过滤掉
null记录:.filter(s -> s.getScore() != null)
想把 key 改成 "pass"/"fail" 而不是 true/false?别用 partitioningBy()
partitioningBy() 的键固定为 Boolean,强行映射字符串会丢失语义和类型安全。此时应该换用 groupingBy():
Map<String, List<Student>> grouped = students.stream()
.collect(Collectors.groupingBy(s -> s.getScore() >= 60 ? "pass" : "fail"));
注意:groupingBy() 在 key 不存在时会创建新 list,而 partitioningBy() 总是保证两个 key 都存在(哪怕对应空 list)。如果你需要“一定有且仅有两个分组”,partitioningBy() 更稳妥;如果要灵活命名或后续扩展更多类别,groupingBy() 才是正解。
性能与并发场景下的注意事项
partitioningBy() 默认使用 HashMap,不保证顺序。如果希望及格组在前、不及格组在后(比如前端渲染顺序敏感),可以传入自定义 Supplier:
Map<Boolean, List<Student>> ordered = students.stream()
.collect(Collectors.partitioningBy(
s -> s.getScore() >= 60,
LinkedHashMap::new, // 保持插入顺序
Collectors.toList()));
在并行流中使用时,partitioningBy() 是线程安全的,但要注意:各线程处理的子流仍会分别生成 true/false 分组,最终合并逻辑由 collector 内部完成——无需额外同步,但不要在 predicate 中修改共享状态。
及格线硬编码在 lambda 里不易维护,实际项目中建议抽成常量或配置项,比如 PassingScore.THRESHOLD,避免散落多处难以统一调整。

















