331. Java Stream API - Java Stream 实战案例:找出合作最多的作者对

331. Java Stream API - Java Stream 实战案例:找出合作最多的作者对

🎯 目标

在一堆文章(Article)中,找出一起合作写文章次数最多的两个作者(Author)


🧩 数据模型设计

我们有三个核心模型:

java 复制代码
// 作者,支持按名字排序
record Author(String name) implements Comparable<Author> {
    public int compareTo(Author other) {
        return this.name.compareTo(other.name);
    }
}

// 文章
record Article(String title, int inceptionYear, List<Author> authors) {}

// 作者对(避免重复,如 A-B 和 B-A 视为同一对)
record PairOfAuthors(Author first, Author second) {
    public static Optional<PairOfAuthors> of(Author first, Author second) {
        // 确保作者对排序一致(避免 A-B 和 B-A)
        if (first.compareTo(second) > 0) {
            return Optional.of(new PairOfAuthors(first, second));
        } else {
            return Optional.empty();
        }
    }
}

📌 PairOfAuthors.of()Optional 表示"是否是有效的作者对",这样可以方便后续的流式处理。


🏗️ 构建作者对流

第一步是:从每篇文章中提取所有合法的作者对。

java 复制代码
BiFunction<Article, Author, Stream<PairOfAuthors>> buildPairOfAuthors =
    (article, firstAuthor) ->
        article.authors().stream()
               .flatMap(secondAuthor ->
                   PairOfAuthors.of(firstAuthor, secondAuthor).stream());

🔍 如果 PairOfAuthors.of() 返回 Optional.empty(),那么 stream() 就是空流,否则是单元素流。这样可以优雅地处理无效对。


🔁 展平所有文章的作者对

java 复制代码
Function<Article, Stream<PairOfAuthors>> toPairOfAuthors =
    article -> article.authors().stream()
                      .flatMap(firstAuthor -> buildPairOfAuthors.apply(article, firstAuthor));

💡 我们对每篇文章的作者使用 flatMap(),构建所有可能的作者对(去除无效)。


📊 构建作者对出现频次的直方图

java 复制代码
Map<PairOfAuthors, Long> numberOfAuthorsTogether =
    articles.stream()
            .flatMap(toPairOfAuthors)
            .collect(Collectors.groupingBy(
                Function.identity(),
                Collectors.counting()));

📦 用 groupingBy + counting() 聚合每对作者出现的次数。


🥇 找出合作最多的一对作者

java 复制代码
Function<Map<PairOfAuthors, Long>, Map.Entry<PairOfAuthors, Long>> maxExtractor =
    map -> map.entrySet().stream()
              .max(Map.Entry.comparingByValue())
              .orElseThrow();

☂️ orElseThrow() 会在没有任何作者对时抛异常,所以要确保至少有一篇文章包含两个作者。


🧪 示例数据和完整运行逻辑

java 复制代码
var maria = new Author("Maria");
var james = new Author("James");
var patricia = new Author("Patricia");
var michael = new Author("Michael");

var articles = List.of(
    new Article("About As You Like It", 2015, List.of(maria)),
    new Article("About King John", 2015, List.of(james)),
    new Article("About The Winter's Tale", 2016, List.of(patricia)),
    new Article("About Richard II", 2017, List.of(michael)),
    new Article("About Richard III", 2019, List.of(maria, patricia)),
    new Article("About Henry VIII", 20219, List.of(patricia, michael)),
    new Article("About Romeo and Juliet", 2020, List.of(maria, patricia, james)),
    new Article("About Macbeth", 2021, List.of(maria, james, michael)),
    new Article("About Hamlet", 2021, List.of(patricia, james, michael)),
    new Article("About King Lear", 2022, List.of(maria, james, patricia, michael))
);

Map.Entry<PairOfAuthors, Long> pair = maxExtractor.apply(numberOfAuthorsTogether);

System.out.println("The authors that published the most together are " +
    pair.getKey().first().name() + " and " + pair.getKey().second().name() +
    ", they wrote " + pair.getValue() + " articles together.");

🧾 输出结果:

java 复制代码
The authors that published the most together are Patricia and Michael, they wrote 3 articles together.

💡 小结与思考

✅ 使用 Optional.stream() 可以优雅处理"可能不存在"的值 ✅ 用 flatMap() 组合嵌套结构(多个 List 变为流) ✅ groupingBy + counting 构建频次统计 ✅ max() + orElseThrow() 获取最大值时要注意异常安全性

相关推荐
mmsx4 分钟前
Android 手簿 ADB 无线调试全攻略:USB 转 WiFi 一键连接
android·前端
jsl_jsl_jsl9 分钟前
LLM工具调用速记
后端
YIAN9 分钟前
手撸社区后端:一套可落地的用户 - 文章 - 互动体系 MySQL 表设计与优化思路
后端·mysql
guwentian11 分钟前
Rolldown vs esbuild vs Webpack:Rust 打包器大战我们该怎么选
前端·webpack·rust·esbuild
ThinkerQAQ_15 分钟前
并发编程(一):先谈硬件——从 count++ 到原子性、可见性与有序性
后端
特立独行的猫A19 分钟前
用纯 Rust 重写 Podcastfy:把网页、PDF 和一段文字,变成一档双人对话播客
前端
岁月如歌778620 分钟前
分布式锁完全指南:从数据库到 Redisson 的演进
java·后端·架构
技术猫22 分钟前
记一次因线程池不合理使用导致生产拨测告警
后端
oooo_z26 分钟前
美股历史K线数据API接口选型指南:iTick覆盖1分钟到月线全周期
服务器·前端·javascript
写后端的胖头鱼29 分钟前
【高频面试题】spring事物失效场景(带原理 + 代码示例)
java·后端·spring·事务·事物失效