本文档详细对比Java Stream API中partitioningBy和groupingBy两个收集器的核心差异。partitioningBy用于二分分组(true/false),返回Map<Boolean, List
partitioningBy vs groupingBy 区别简答:partitioningBy 是 二分(true/false,基于 Predicate),返回 Map<Boolean, List<T>>;groupingBy 是 多分组(任意 key 类型),返回 Map<K, List<T>>。partitioningBy 是 groupingBy 的高效特化(一次遍历、boolean key),优先二分用 partitioningBy。
| 特性 | partitioningBy(Predicate) | groupingBy(Function/Classifier) |
|——————-|————————————————|————————————————-|
| 分组方式 | 固定二分(true/false) | 任意多分组(key 类型任意) |
| 返回类型 | Map<Boolean, List<T>> | Map<K, List<T>>(K=classifier.apply(T)) |
| Classifier | Predicate
partitioningBy = groupingBy(predicate::test) 的优化版。输入:List<String> list = List.of("a", "apple", "banana", "app", "bat");
partitioningBy:按长度 >3 二分Map<Boolean, List<String>> part = list.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 3));
List<String> longOnes = part.get(true); // [apple, banana]
List<String> shortOnes = part.get(false); // [a, app, bat]
groupingBy:按长度多分组Map<Integer, List<String>> group = list.stream()
.collect(Collectors.groupingBy(String::length));
group.get(1); // [a]
group.get(3); // [app, bat]
group.get(5); // [apple]
group.get(6); // [banana]
输出差异:
两者都支持 downstream(二级收集),如计数、Set、Map。
// partitioningBy + counting(统计 true/false 数量)
Map<Boolean, Long> partCount = list.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 3, Collectors.counting()));
// {false=3, true=2}
// groupingBy + counting(每个组计数)
Map<Integer, Long> groupCount = list.stream()
.collect(Collectors.groupingBy(String::length, Collectors.counting()));
// {1=1, 3=2, 5=1, 6=1}
// partitioningBy + toSet(去重)
Map<Boolean, Set<String>> partSet = list.stream()
.collect(Collectors.partitioningBy(s -> s.startsWith("a"), Collectors.toSet()));
// groupingBy 多级:先长度,再首字母
Map<Integer, Map<Character, List<String>>> nested = list.stream()
.collect(Collectors.groupingBy(
String::length,
Collectors.groupingBy(s -> s.charAt(0))
));
// {1={a=[a]}, 3={a=[app], b=[bat]}, ...}
partitioningBy 无此(需嵌套使用)。
| 场景 | 选 partitioningBy | 选 groupingBy |
|———————–|———————–|——————-|
| 二分组(>13/<13)| ✅ 首选 | ❌ 过度 |
| 多分组(区间) | ❌ | ✅ |
| 大数据/并行 | ✅(boolean 快) | ✅ |
| 动态 key | ❌ | ✅(Function) |
| null 安全 | 加 filter(Objects::nonNull) | 同左 |
toUnmodifiableMap()(Java 10+)。partitioningBy 后用 groupingBy 嵌套。
Map<Boolean, Map<Integer, List<String>>> hybrid = list.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 3,
Collectors.groupingBy(String::length)));
Files.readAllLines().collect(partitioningBy(line -> line.startsWith("#")))。完整测试:
assertEquals(2, splitByLength(original, 13).get(true).size()); // partitioningBy
如果需要性能基准代码、自定义 Collector,或特定场景优化,提供细节我可以扩展!