275. Java Stream API - flatMap 操作:展开一对多的关系,拉平你的流!

275. Java Stream API - flatMap 操作:展开一对多的关系,拉平你的流!


🧠 背景:我们为什么需要 flatMap

假设我们有以下结构:

  • 每个 Country 拥有多个 City
  • 每个 City 有一个人口数 population

我们的目标是:统计所有城市的总人口数

最直接的写法当然是嵌套 for 循环

java 复制代码
int totalPopulation = 0;
for (Country country : countries) {
    for (City city : country.cities()) {
        totalPopulation += city.population();
    }
}
System.out.println("Total population = " + totalPopulation);

📌 输出:

java 复制代码
Total population = 24493

虽然有效,但 Java 8 之后我们有了更优雅的方式:使用流 + flatMap 来处理一对多的关系


🔁 用 flatMap 优雅替代嵌套循环

✅ 定义模型结构

java 复制代码
record City(String name, int population) {}
record Country(String name, List<City> cities) {}

✅ 初始化数据

java 复制代码
City newYork = new City("New York", 8_258);
City losAngeles = new City("Los Angeles", 3_821);
Country usa = new Country("USA", List.of(newYork, losAngeles));

City london = new City("London", 8_866);
City manchester = new City("Manchester", 568);
Country uk = new Country("United Kingdom", List.of(london, manchester));

City paris = new City("Paris", 2_103);
City marseille = new City("Marseille", 877);
Country france = new Country("France", List.of(paris, marseille));

List<Country> countries = List.of(usa, uk, france);

🚀 使用 flatMap 重写统计逻辑

java 复制代码
int totalPopulation = countries.stream()
                               .flatMap(country -> country.cities().stream())  // 展开所有城市
                               .mapToInt(City::population)                     // 提取人口
                               .sum();                                         // 累加总人口

System.out.println("Total population = " + totalPopulation);

📌 输出:

java 复制代码
Total population = 24493

🔍 flatMap 是如何工作的?

flatMap 是两个操作的组合:

步骤 1️⃣:映射(map)

java 复制代码
country -> country.cities().stream()

这一步将每个 Country 映射为它的城市流,得到的是一个 Stream<Stream<City>>(流的流)。


步骤 2️⃣:展平(flat)

flatMap自动帮你把多个子流合并为一个连续的扁平流Stream<City>),这样你就可以对所有城市统一处理!

🎯 类比图示:

java 复制代码
Stream<Country>  ---映射--->  Stream<Stream<City>>
                     |
                     +--->  展平(flatten)--->  Stream<City>

📚 延伸案例:Map 结构的 flatMap

假设我们有一个 Continent 类型,它包含一个 Map:

java 复制代码
record Continent(Map<String, Country> countries) {}

此时,如果你想从 Continent 中提取所有国家,可以这样写:

java 复制代码
Function<Continent, Stream<Country>> continentToCountry =
    continent -> continent.countries().values().stream();

再进一步,还可以这样嵌套 flatMap

java 复制代码
int total = continents.stream()
                      .flatMap(continent -> continent.countries().values().stream())
                      .flatMap(country -> country.cities().stream())
                      .mapToInt(City::population)
                      .sum();

🧠 小结:flatMap 用法口诀

用法场景 对应方法
一对一映射(每个元素 → 单个新值) .map()
一对多映射(每个元素 → 多个新值) .flatMap()
提取嵌套集合中的内容并扁平化 .flatMap()
转换成基础类型流(int/long/double .mapToInt()

🧪 练习建议(课堂可选)

❓ 问题:下面代码的输出是什么?

java 复制代码
List<String> words = List.of("java", "stream", "api");

List<Character> chars = words.stream()
                             .flatMap(word -> word.chars().mapToObj(c -> (char) c))
                             .toList();

System.out.println(chars);

🎯 答案:

java 复制代码
[j, a, v, a, s, t, r, e, a, m, a, p, i]
相关推荐
源代码•宸1 分钟前
Golang语法进阶(定时器)
开发语言·经验分享·后端·算法·golang·timer·ticker
小Tomkk2 分钟前
⭐️ StarRocks Web 使用介绍与实战指南
前端·ffmpeg
计算机学姐5 分钟前
基于SpringBoot的汽车租赁系统【个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·spring·汽车·推荐算法
不一样的少年_6 分钟前
产品催: 1 天优化 Vue 官网 SEO?我用这个插件半天搞定(不重构 Nuxt)
前端·javascript·vue.js
-dcr8 分钟前
50.智能体
前端·javascript·人工智能·ai·easyui
好好研究8 分钟前
SpringBoot小案例打包执行流程
java·spring boot·后端
BingoGo9 分钟前
免费可商用商业级管理后台 CatchAdmin V5 正式发布 插件化与开发效率的全面提升
vue.js·后端·php
行者9617 分钟前
Flutter跨平台开发适配OpenHarmony:进度条组件的深度实践
开发语言·前端·flutter·harmonyos·鸿蒙
云和数据.ChenGuang18 分钟前
Uvicorn 是 **Python 生态中用于运行异步 Web 应用的 ASGI 服务器**
服务器·前端·人工智能·python·机器学习
IT_陈寒20 分钟前
SpringBoot 3.0实战:这5个新特性让你的开发效率提升50%
前端·人工智能·后端