note

文档概述

本文档详细对比Java Stream API中partitioningBy和groupingBy两个收集器的核心差异。partitioningBy用于二分分组(true/false),返回Map<Boolean, List>;groupingBy用于多分组,返回Map<K, List>。文档涵盖功能对比、代码示例、高级用法、性能分析和最佳实践,帮助开发者根据场景选择合适的分组策略。

使用场景

Java Stream:partitioningBy vs groupingBy 区别

简答partitioningBy二分(true/false,基于 Predicate),返回 Map<Boolean, List<T>>groupingBy多分组(任意 key 类型),返回 Map<K, List<T>>partitioningBygroupingBy高效特化(一次遍历、boolean key),优先二分用 partitioningBy

1. 核心差异对比

| 特性 | partitioningBy(Predicate) | groupingBy(Function/Classifier) | |——————-|————————————————|————————————————-| | 分组方式 | 固定二分(true/false) | 任意多分组(key 类型任意) | | 返回类型 | Map<Boolean, List<T>> | Map<K, List<T>>(K=classifier.apply(T)) | | Classifier | Predicate | Function<T, K> | | **遍历次数** | **1 次**(高效) | 1 次(相同) | | **下游收集器** | 支持(如 `toSet()`、`counting()`) | 支持(更灵活) | | **适用场景** | **Yes/No、奇偶、大小** 等二元分类 | **多类分组**(长度区间、类型、枚举) | | **内存/性能** | **更优**(boolean key 无 hash 开销) | 略高(任意 key hash) |

2. 基础代码示例(相同输入)

输入: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]

输出差异

3. 高级用法:下游收集器(相同支持)

两者都支持 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()));

4. 多级分组(groupingBy 独强)

// 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 无此需嵌套使用)。

5. 性能 & 选择 Checklist

| 场景 | 选 partitioningBy | 选 groupingBy | |———————–|———————–|——————-| | 二分组(>13/<13)| ✅ 首选 | ❌ 过度 | | 多分组(区间) | ❌ | ✅ | | 大数据/并行 | ✅(boolean 快) | ✅ | | 动态 key | ❌ | ✅(Function) | | null 安全 | 加 filter(Objects::nonNull) | 同左 |

6. 最佳实践建议

完整测试

assertEquals(2, splitByLength(original, 13).get(true).size()); // partitioningBy

如果需要性能基准代码、自定义 Collector,或特定场景优化,提供细节我可以扩展!


← 返回文档首页