Stream 数据统计实战:求和、平均值、分组汇总(AI 辅助学习 Java 8)

前三篇学了 Collectors、flatMap。今天在一个完整的博客数据场景中,综合运用 Stream + Collectors 实现数据统计、分组汇总、标签云、趋势分析。


一、整体概览:一键获取所有统计信息

java 复制代码
IntSummaryStatistics stats = blogs.stream()
        .collect(Collectors.summarizingInt(BlogData::getViews));

stats.getCount();    // 7 篇文章
stats.getSum();      // 2180 总阅读
stats.getAverage();  // 311 平均阅读
stats.getMax();      // 500 最高阅读
stats.getMin();      // 180 最低阅读

一次遍历获取所有统计信息,比分别调用五次高效。

二、按作者分组汇总

java 复制代码
Map<String, AuthorSummary> summaries = blogs.stream()
        .collect(Collectors.groupingBy(
                BlogData::getAuthor,
                Collectors.collectingAndThen(
                        Collectors.toList(),
                        list -> new AuthorSummary(
                                list.size(),                                          // 文章数
                                list.stream().mapToInt(BlogData::getViews).sum(),     // 总阅读
                                list.stream().mapToInt(BlogData::getViews).average().orElse(0), // 平均阅读
                                list.stream().mapToInt(BlogData::getViews).max().orElse(0),     // 最高阅读
                                list.stream().filter(BlogData::isPublished).count()   // 已发布数
                        )
                )
        ));

输出:

makefile 复制代码
张三: 文章 3 篇 (已发布: 2), 总阅读: 730, 平均: 243, 最高: 350
李四: 文章 2 篇 (已发布: 2), 总阅读: 900, 平均: 450, 最高: 500
王五: 文章 2 篇 (已发布: 1), 总阅读: 550, 平均: 275, 最高: 300

三、标签云:flatMap + groupingBy + 排序

java 复制代码
// 统计标签频率
Map<String, Long> tagFrequency = blogs.stream()
        .flatMap(b -> b.getTags().stream())
        .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));

// 按频率降序展示
tagFrequency.entrySet().stream()
        .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
        .forEach(e -> System.out.println("  " + e.getKey() + " (" + e.getValue() + ")"));

输出:

scss 复制代码
Java (4)
前端 (2)
Optional (1)
Docker (1)
Vue (1)
...

四、趋势分析:排序 + Top N

阅读量 Top 3

java 复制代码
blogs.stream()
        .sorted(Comparator.comparingInt(BlogData::getViews).reversed())
        .limit(3)
        .forEach(b -> System.out.println("  " + b.getTitle() + " (" + b.getViews() + ")"));

最低阅读量的已发布文章

java 复制代码
blogs.stream()
        .filter(BlogData::isPublished)
        .min(Comparator.comparingInt(BlogData::getViews))
        .ifPresent(b -> System.out.println("  " + b.getTitle() + " (" + b.getViews() + ")"));

五、运行结果

ini 复制代码
=== 整体概览 ===
  文章总数: 7
  总阅读量: 2180
  平均阅读: 311
  最高: 500 / 最低: 180

=== 按作者汇总 ===
  张三: 3 篇, 总阅读 730, 平均 243, 最高 350
  李四: 2 篇, 总阅读 900, 平均 450, 最高 500
  王五: 2 篇, 总阅读 550, 平均 275, 最高 300

=== 按分类统计 ===
  Java: 4 篇
  前端: 2 篇
  运维: 1 篇
  各分类平均阅读: {Java=257.5, 运维=250.0, 前端=450.0}

=== 标签云 ===
  Java #### (4)
  前端 ## (2)
  Stream # (1)
  ...

=== 趋势分析 ===
  阅读量 Top 3:
    Vue3 API (500 阅读)
    React Hooks (400 阅读)
    Stream 详解 (350 阅读)

六、本周学习总结

第四周我们学习了 Collectors 进阶,完整路线:

bash 复制代码
周二:Collectors 全家桶------toList/joining/groupingBy/partitioningBy/summarizing
周四:flatMap 深入------一对多场景、标签提取、反向索引
周六:数据统计实战------求和、平均值、分组汇总、标签云(本篇)

核心收获

知识点 关键方法 一句话
toList/toSet/toMap 转集合 收集为数据结构
joining 拼接字符串 带分隔符、前后缀
groupingBy 分组 按条件分组 + 下游收集器
partitioningBy 分区 按 true/false 分两组
summarizing 汇总统计 一次获取 count/sum/avg/max/min
flatMap 扁平化 一对多场景的利器
collectingAndThen 后处理 分组后自定义转换

七、下周预告

第五周进入 Optional,学习如何优雅地处理空值,告别 NullPointerException。


系列文章导航

相关推荐
65岁退休Coder30 分钟前
LangGraph v1.2.9 节点容错策略 & 流式输出 & 持久化记忆管理
后端·python·langchain
涛涛ing1 小时前
OpenAI Astra 泄露:零样本生成 3D 网页,前端开发者慌了吗?
前端
ssshooter2 小时前
现在网页都能提供 MCP 了?!
前端·人工智能·程序员
杉氧2 小时前
状态管理变迁史:为什么我们放弃了 Redux 选择 Zustand?
android·前端·react native
cidy_982 小时前
OpenCode 手动配置火山方舟 Agent Plan 教程
前端
鹏多多2 小时前
PC 网站接入微信登录,这 10 个坑我替你踩完了!
前端·javascript·vue.js
律宏阔2 小时前
微信小程序使用 Orval + OpenAPI 自动生成接口:Axios 兼容踩坑记录
前端·微信小程序
律宏阔2 小时前
微信小程序集成 TDesign 完整记录:解决 NPM packages not found
前端·微信小程序
元界metalite2 小时前
SpringBoot整合RocketMQ-毒丸消息还要无限重试吗
后端
律宏阔2 小时前
微信小程序 ECharts 瘦身实战:分包异步化 + componentPlaceholder 避开主包 2MB 限制
前端·微信小程序