332. Java Stream API - Java Stream 实战进阶:按年份找出合作最多的作者对

332. Java Stream API - Java Stream 实战进阶:按年份找出合作最多的作者对


🎯 目标升级版

之前我们找出了合作最多的两位作者 ,现在我们想再进一层: 👉 按年份(inceptionYear)统计每年合作次数最多的作者对!


💡 核心思路

我们要构建一个这样的结构:

java 复制代码
Map<Integer, Map.Entry<PairOfAuthors, Long>>

其中:

  • Integer 是年份;
  • PairOfAuthors 是两位作者的组合;
  • Long 是他们在该年合写的文章数量。

🧰 技术点复用:我们已经有了这些组件

  1. 作者对生成器 toPairOfAuthors:将一篇文章中所有作者组合为 PairOfAuthors
  2. 分组计数器 groupingBy + counting:统计某个作者对出现的次数
  3. 最大值提取器:从 Map 中取出合作次数最多的那一对

🏗️ Step 1:创建中间 Collector

先把"作者对 -> 次数"的 collector 和"取最大"的 finisher 拆出来:

java 复制代码
// 构建频率直方图
Collector<PairOfAuthors, ?, Map<PairOfAuthors, Long>> groupingBy =
    Collectors.groupingBy(Function.identity(), Collectors.counting());

// 提取出现最多的作者对
Function<Map<PairOfAuthors, Long>, Map.Entry<PairOfAuthors, Long>> finisher =
    map -> {
    if (map.isEmpty()) {
        // 返回默认值而不是抛出异常
        return Map.entry(new PairOfAuthors(new Author("None"), new Author("None")), 0L);
    }
    return map.entrySet().stream()
        .max(Map.Entry.comparingByValue())
        .orElseThrow();
};

🧪 Step 2:合并为单个 collector:collectingAndThen

我们将 groupingBy + finisher 合成一个终极 Collector:

java 复制代码
Collector<PairOfAuthors, ?, Map.Entry<PairOfAuthors, Long>> pairOfAuthorsEntryCollector =
    Collectors.collectingAndThen(
        groupingBy,
        finisher
    );

collectingAndThen 可以让你对收集结果做后处理。


🧬 Step 3:让 flatMap 成为 Collector:flatMapping()

我们还可以将作者对的 flatMap 操作也变成 collector:

java 复制代码
Collector<Article, ?, Map.Entry<PairOfAuthors, Long>> flatMapping =
    Collectors.flatMapping(
        toPairOfAuthors,                     // 元素转换:每篇文章展开为作者对流
        pairOfAuthorsEntryCollector          // 收集逻辑:计数并提取最大对
    );

🔍 注意:flatMapping 只有在 JDK 12+ 才支持,需确保运行环境。


🧭 Step 4:按年份分组,应用 flatMapping 作为 downstream

java 复制代码
Map<Integer, Map.Entry<PairOfAuthors, Long>> result =
    articles.stream()
            .collect(Collectors.groupingBy(
                Article::inceptionYear,      // 分组依据:年份
                flatMapping                  // 每组处理逻辑
            ));

🎯 现在你就得到了每一年的"合作次数最多的作者对"。


🧪 示例输出(模拟)

java 复制代码
result.forEach((year, pair) -> {
    System.out.println(year + ": " +
        pair.getKey().first().name() + " + " +
        pair.getKey().second().name() + " -> " +
        pair.getValue() + " times");
});

🖨️ 假设输出:

java 复制代码
2019: Maria + Patricia -> 1 times
2020: Maria + James -> 2 times
2021: Patricia + Michael -> 2 times
2022: Maria + James -> 3 times

📦 总结归纳

步骤 技术点 说明
1️⃣ flatMapflatMapping() 把转换操作变为 collector
2️⃣ groupingBycollectingAndThen() 把聚合和提取最大合并
3️⃣ groupingBy(year, downstream) 多级分组并传入下游 collector
4️⃣ .orElseThrow() 安全性 记得对空数据做容错处理

💬 类比讲解

📦 想象你是在统计每年的合作之"最":

  • 每篇文章像是一张会议签到表;
  • 我们找出所有同时签名的两个人;
  • 然后按年份分组,统计谁签的最多;
  • 最后找出每年"最亲密搭档"。
相关推荐
LucianaiB11 分钟前
【Dify + EdgeOne】你奶奶也会做一个“智票通”,轻松票据自定义提取+防数据泄露
前端·后端
python在学ing15 分钟前
前端-CSS学习笔记
前端·css·python·学习
Bug-制造者27 分钟前
【Vue3 实战】全局错误处理体系搭建:实现业务与错误彻底解耦
前端·javascript·vue.js
程序员老邢30 分钟前
【技术底稿 37】Spring Boot 3.x 自动装配 “死锁” 排查:3 个注解实现条件化装配与 Mock 兜底
java·spring boot·后端·自动装配·rag·技术底稿
悟空瞎说31 分钟前
# Git 交互式变基:优雅整理提交历史,告别杂乱 PR 记录
前端·git
用户4343092416937 分钟前
Day29:图片上传 + 存数据库(Multer + MySQL)
数据库·后端
码路高手42 分钟前
Hermes Agent 整体了解
后端·架构
还有多久拿退休金43 分钟前
DragSortTable:一个让我怀疑人生的滚动重置 Bug
前端
日月云棠1 小时前
JAVA数据结构与算法 - 基础:链表
java·后端
渐儿1 小时前
组件库开发入门到生产(从零封装到 npm 发布)
前端