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() 安全性 记得对空数据做容错处理

💬 类比讲解

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

  • 每篇文章像是一张会议签到表;
  • 我们找出所有同时签名的两个人;
  • 然后按年份分组,统计谁签的最多;
  • 最后找出每年"最亲密搭档"。
相关推荐
xiaofeichaichai2 小时前
Webpack
前端·webpack·node.js
GetcharZp2 小时前
GitHub 49K+ Star!C++ 开发者必知的 JSON 神级库:从零到精通全指北
后端
问心无愧05132 小时前
ctf show web入门111
android·前端·笔记
xujinwei_gingko2 小时前
SpringBoot整合WebSocket
spring boot·后端·websocket
唐某人丶2 小时前
模型越来越强,我们还需要 Agent 工程吗?—— 从价值重估到 Harness 实践
前端·agent·ai编程
智码看视界2 小时前
现代Web开发基础:全栈工程师的起航点
前端·后端·c5全栈
程序员cxuan2 小时前
Claude Fable 5 来了
人工智能·后端·程序员
JS菌3 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
wang09073 小时前
自己动手写一个spring之IOC_2
java·后端·spring