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() 获取最大值时要注意异常安全性

相关推荐
小圣贤君5 小时前
在 Electron 里造一个「搜书 + 下载」:从 so-novel 到 51mazi 的爬虫实践
前端·人工智能·爬虫·electron·ai写作·小说下载·网文下载
Java编程爱好者5 小时前
如何将 Spring Statemachine 作为一个轻量级工作流引擎来使用?
后端
祁梦5 小时前
Redis从入门到入土 --- 黑马点评点赞功能实现详解
java·后端
Java编程爱好者5 小时前
Java8 HashMap高低位拆分扩容,核心逻辑一次性说清
后端
淘源码d5 小时前
基于Spring Boot + Vue的诊所管理系统(源码)全栈开发指南
java·vue.js·spring boot·后端·源码·门诊系统·诊所系统
iPadiPhone5 小时前
Java 反射机制底层原理、面试陷阱与实战指南
java·开发语言·后端·面试
iPadiPhone5 小时前
Java SPI 机制全链路深度解析与面试通关指南
java·后端·面试
神奇小汤圆5 小时前
Spring Boot中获取真实客户端IP的终极方案,99%的人都没做对!
后端
小杍随笔5 小时前
【Rust 1.94.0 正式发布:数组窗口、Cargo 配置模块化、TOML 1.1 全面升级|开发者必看】
开发语言·后端·rust
掘金安东尼5 小时前
⏰前端周刊第 456 期(v2026.3.15)
前端·javascript·面试