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

相关推荐
小码编匠2 小时前
WPF 如何在 MVVM模式下实现 DataGrid编辑功能
后端·c#·.net
锅包一切2 小时前
二、几种安装类型
linux·运维·后端·操作系统
We་ct2 小时前
LeetCode 129. 求根节点到叶节点数字之和:两种解法详解(栈+递归)
前端·算法·leetcode·typescript
Joker Zxc2 小时前
【前端基础(Javascript部分)】1、JavaScript的基础知识(组成、应用、编写方式、注释)
开发语言·前端·javascript
Hoffer_2 小时前
更好理解ORDER BY内部排序和性能优化-mysql
后端·mysql
HelloReader2 小时前
Tauri 项目结构前端壳 + Rust 内核,怎么协作、怎么构建、怎么扩展
前端
Penge6662 小时前
Go 语言 defer:你需要掌握的三个核心要点
后端
HelloReader2 小时前
Tauri 前端配置把任何前端框架“正确地”接进 Tauri(含 Vite/Next/Nuxt/Qwik/SvelteKit/Leptos/Trunk)
前端
言午说数据2 小时前
Spark SQL练习2-电商用户行为分析
后端