315. Java Stream API - 使用 Collectors.groupingBy() 对流元素分组 —— 创建分组映射和直方图的利器

文章目录

  • [315. Java Stream API - 使用 `Collectors.groupingBy()` 对流元素分组 ------ 创建分组映射和直方图的利器](#315. Java Stream API - 使用 Collectors.groupingBy() 对流元素分组 —— 创建分组映射和直方图的利器)
    • [✅ 基本用法:将流元素按分类器函数分组](#✅ 基本用法:将流元素按分类器函数分组)
      • [🧠 什么是分类器?](#🧠 什么是分类器?)
      • [📌 基本示例:按字符串长度分组](#📌 基本示例:按字符串长度分组)
      • [💡 输出结果:](#💡 输出结果:)
    • [✅ 进阶用法一:使用下游收集器 `counting()` 统计每组元素数量](#✅ 进阶用法一:使用下游收集器 counting() 统计每组元素数量)
      • [💡 输出结果:](#💡 输出结果:)
    • [✅ 进阶用法二:使用下游收集器 `joining()` 拼接每组字符串](#✅ 进阶用法二:使用下游收集器 joining() 拼接每组字符串)
      • [💡 输出结果:](#💡 输出结果:)
    • [✅ 高阶用法:自定义 Map 类型(第三个参数)](#✅ 高阶用法:自定义 Map 类型(第三个参数))
      • [💡 输出结果(按 key 排序):](#💡 输出结果(按 key 排序):)
    • [🧠 小结回顾](#🧠 小结回顾)
    • [🚀 实际应用场景](#🚀 实际应用场景)

315. Java Stream API - 使用 Collectors.groupingBy() 对流元素分组 ------ 创建分组映射和直方图的利器

在 Java 的 Stream API 中,Collectors.groupingBy() 是一个非常核心的收集器,用于将流中的元素按照某种规则进行分组,并构建一个 Map。你可以利用它创建直方图(Histogram)、分组统计表、分组连接字符串等,灵活性非常强。


✅ 基本用法:将流元素按分类器函数分组

🧠 什么是分类器?

groupingBy() 的第一个参数是一个分类器(classifier)函数 ,它定义了如何为每个流元素生成分组的键(key)。这个键可以是任意类型(不能为 null),只要能对元素进行合理的分类。

📌 基本示例:按字符串长度分组

java 复制代码
Collection<String> strings = List.of("one", "two", "three", "four", "five", "six", 
                                     "seven", "eight", "nine", "ten", "eleven", "twelve");

Map<Integer, List<String>> map = strings.stream()
    .collect(Collectors.groupingBy(String::length));

map.forEach((key, value) -> System.out.println(key + " :: " + value));

💡 输出结果:

java 复制代码
3 :: [one, two, six, ten]
4 :: [four, five, nine]
5 :: [three, seven, eight]
6 :: [eleven, twelve]

🧩 String::length 就是分类器,它把每个字符串按长度分组。结果是一个 Map<Integer, List<String>>,键为长度,值为对应长度的字符串列表。


✅ 进阶用法一:使用下游收集器 counting() 统计每组元素数量

你可以为 groupingBy() 提供一个下游收集器(downstream collector) ,用于进一步处理每个分组的值。比如统计每组中元素的个数,就可以使用 Collectors.counting()

java 复制代码
Map<Integer, Long> map = strings.stream()
    .collect(Collectors.groupingBy(
        String::length,
        Collectors.counting()
    ));

map.forEach((key, value) -> System.out.println(key + " :: " + value));

💡 输出结果:

java 复制代码
3 :: 4
4 :: 3
5 :: 3
6 :: 2

📊 这就构成了一个按字符串长度统计数量的直方图(Histogram)!非常适用于词频统计、日志分析等场景。


✅ 进阶用法二:使用下游收集器 joining() 拼接每组字符串

如果你希望每个分组的字符串不是以列表的形式展示,而是以逗号分隔的字符串形式呈现,可以使用 Collectors.joining()

java 复制代码
Map<Integer, String> map = strings.stream()
    .collect(Collectors.groupingBy(
        String::length,
        Collectors.joining(", ")
    ));

map.forEach((key, value) -> System.out.println(key + " :: " + value));

💡 输出结果:

java 复制代码
3 :: one, two, six, ten
4 :: four, five, nine
5 :: three, seven, eight
6 :: eleven, twelve

📎 非常适合用于打印清晰的报告或日志输出。


✅ 高阶用法:自定义 Map 类型(第三个参数)

有时候你可能不希望使用默认的 HashMap,而想用 TreeMap(按键排序)或 LinkedHashMap(保持插入顺序)。这时候可以使用 groupingBy() 的第三个重载版本,手动传入一个 Map 工厂(Supplier<Map>):

java 复制代码
Map<Integer, List<String>> map = strings.stream()
    .collect(Collectors.groupingBy(
        String::length,
        TreeMap::new, // 指定用 TreeMap
        Collectors.toList()
    ));

map.forEach((key, value) -> System.out.println(key + " :: " + value));

💡 输出结果(按 key 排序):

java 复制代码
3 :: [one, two, six, ten]
4 :: [four, five, nine]
5 :: [three, seven, eight]
6 :: [eleven, twelve]

📦 注意:默认 groupingBy() 使用的是 HashMap,如果你对顺序有要求,一定要使用此重载!


🧠 小结回顾

用法 示例 返回类型
基本分组 .groupingBy(String::length) Map<Integer, List<String>>
分组计数 .groupingBy(String::length, counting()) Map<Integer, Long>
分组连接 .groupingBy(String::length, joining(", ")) Map<Integer, String>
自定义Map类型 .groupingBy(String::length, TreeMap::new, toList()) TreeMap<Integer, List<String>>

🚀 实际应用场景

  • 📊 构建分类直方图(如词长统计、订单状态分类)
  • 📋 按属性分类列表(如按部门分组员工)
  • 🧾 按属性汇总信息(如每类产品的总销售额)

如果你希望在讲解中更加生动,还可以举一个现实世界的例子,比如:

"就像我们把学生按成绩分等级一样,groupingBy() 就是在说:'把所有分数在90分以上的放到优秀组,60分以下的放到不及格组......' 这样我们就有了一个分组清单,还可以数一数每组有多少人,甚至把他们的名字拼起来打印。"

相关推荐
寻寻觅觅☆9 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
l1t10 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
青云计划10 小时前
知光项目知文发布模块
java·后端·spring·mybatis
赶路人儿10 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar12311 小时前
C++使用format
开发语言·c++·算法
探路者继续奋斗11 小时前
IDD意图驱动开发之意图规格说明书
java·规格说明书·开发规范·意图驱动开发·idd
码说AI11 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS11 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
星空下的月光影子11 小时前
易语言开发从入门到精通:补充篇·网络爬虫与自动化采集分析系统深度实战·HTTP/HTTPS请求·HTML/JSON解析·反爬策略·电商价格监控·新闻资讯采集
开发语言
老约家的可汗11 小时前
初识C++
开发语言·c++