Collectors.partitioningBy()用于布尔二分,返回true/false键的Map;groupingBy()按分类函数分多组;切片应避免subList()陷阱,需深拷贝防并发问题。

用 Collectors.partitioningBy() 做二分:条件成立 / 不成立
这是最常用也最轻量的分割方式,适用于「非此即彼」的布尔判断。它返回一个 Map,true 键对应满足条件的元素,false 键对应不满足的。
- 必须传入一个
Predicate,比如x -> x > 10或String::isEmpty - 底层是单次遍历,性能好;但只能分两组,不能扩展为三组或更多
- 注意空集合不会报错,但若流本身为
null,会抛NullPointerException - 示例:
List
结果中nums = Arrays.asList(1, 12, 5, 18, 3); Map > parts = nums.stream() .collect(Collectors.partitioningBy(x -> x > 10)); parts.get(true)是[12, 18]
用 Collectors.groupingBy() 按分类函数分组
当你需要按某个属性、计算结果或枚举值把集合拆成多组(不限于两个),就该用这个。它返回 Map,键由你提供的分类函数决定。
- 分类函数返回值将作为分组键,所以要注意其
equals()和hashCode()行为(比如用自定义对象作键需重写) - 默认分组值是
ArrayList,如需控制顺序或类型,可额外传入下游收集器,例如groupingBy(keyFn, LinkedHashMap::new, toList()) - 如果分类函数返回
null,会触发NullPointerException(除非用Collectors.groupingByConcurrent()并配合Function.identity()等容错设计) - 示例:
Map
> byDept = people.stream() .collect(Collectors.groupingBy(p -> p.getDepartment().getName()));
手动实现多条件切片:避免 subList() 的陷阱
有人误以为「分割」就是按索引切片(比如每 10 个一组),但这和条件分割本质不同。若真要按数量分块,别直接用 list.subList() 循环——它返回的是原列表的视图,修改子列表会影响原列表,且并发下不安全。
- 正确做法是用
Stream.iterate()+limit()构造索引段,再映射取子集并转为新ArrayList - 更稳妥的是引入
Lists.partition()(Guava)或StreamUtils.chunked()(Apache Commons Collections 4.4+) - 自己写工具方法时,注意边界检查:末尾不足一块时不能越界,
fromIndex和toIndex都要Math.min(..., list.size()) - 示例(无依赖纯 Java):
public static
List - > partition(List
list, int size) { return IntStream.iterate(0, i -> i < list.size(), i -> i + size) .mapToObj(i -> list.subList(i, Math.min(i + size, list.size()))) .map(ArrayList::new) .collect(Collectors.toList()); }
条件分割时容易忽略的 null 和并发问题
真实业务中,集合元素常含 null,而多数条件函数(如 Objects.nonNull())虽能处理,但一旦混用 Optional 或方法引用(如 String::length),就会在 null 元素上抛 NullPointerException。
立即学习“Java免费学习笔记(深入)”;
- 务必在流开始处加
.filter(Objects::nonNull),或在条件函数里显式判空(如x -> x != null && x.isActive()) - 若原始集合可能被其他线程修改,不要对它直接调用
stream()—— 应先复制:new ArrayList(originalList).stream() -
parallelStream()虽快,但partitioningBy和groupingBy默认使用HashMap,不是线程安全的;如需并发,改用groupingByConcurrent()或手动同步 - 特别提醒:
Collectors.toMap()类分割操作在 key 冲突时默认抛异常,而partitioningBy和groupingBy不会,这点常被忽略










