332. Java Stream API - Java Stream 实战进阶:按年份找出合作最多的作者对
🎯 目标升级版
之前我们找出了合作最多的两位作者 ,现在我们想再进一层: 👉 按年份(inceptionYear)统计每年合作次数最多的作者对!
💡 核心思路
我们要构建一个这样的结构:
java
Map<Integer, Map.Entry<PairOfAuthors, Long>>
其中:
Integer是年份;PairOfAuthors是两位作者的组合;Long是他们在该年合写的文章数量。
🧰 技术点复用:我们已经有了这些组件
- 作者对生成器
toPairOfAuthors:将一篇文章中所有作者组合为PairOfAuthors - 分组计数器
groupingBy + counting:统计某个作者对出现的次数 - 最大值提取器:从 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️⃣ | flatMap ➜ flatMapping() |
把转换操作变为 collector |
| 2️⃣ | groupingBy ➜ collectingAndThen() |
把聚合和提取最大合并 |
| 3️⃣ | groupingBy(year, downstream) |
多级分组并传入下游 collector |
| 4️⃣ | .orElseThrow() 安全性 |
记得对空数据做容错处理 |
💬 类比讲解
📦 想象你是在统计每年的合作之"最":
- 每篇文章像是一张会议签到表;
- 我们找出所有同时签名的两个人;
- 然后按年份分组,统计谁签的最多;
- 最后找出每年"最亲密搭档"。