Stream 流中 flatMap 方法详解

🎯 1. flatMap() 到底是啥?

flatMap()Stream 里的中间操作,它的作用可以分两步理解:

  • 第一步:对流里的每个元素,先**映射(转换)**成一个 Stream
  • 第二步:把多个子流拍平成一个大的扁平流。

简单记忆map() 是一对一,flatMap() 是一对多。


🛠️ 2. 基础用法拆解

来看个例子:

List<String> list = List.of("Hello World", "Java Stream");List<String> result = list.stream().map(s -> s.split(" "))   // 转成 String[] 流.flatMap(Arrays::stream)    // 拍平成单层流.collect(Collectors.toList());System.out.println(result);

执行过程解析

步骤操作结果
🎯 map()每个元素转成数组[["Hello", "World"], ["Java", "Stream"]]
🔥 flatMap()拍平成单层流["Hello", "World", "Java", "Stream"]

🔍 3. map() vs flatMap() 的区别

我们用个更直观的对比例子:

List<String> list = List.of("a,b,c", "d,e,f");// map()
List<String[]> mapResult = list.stream().map(s -> s.split(","))  // 每个元素变成 String[].collect(Collectors.toList());System.out.println(mapResult);
// 输出: [[a, b, c], [d, e, f]]  (嵌套数组)// flatMap()
List<String> flatMapResult = list.stream().flatMap(s -> Arrays.stream(s.split(","))).collect(Collectors.toList());System.out.println(flatMapResult);
// 输出: [a, b, c, d, e, f] (扁平化的一层)

总结

功能map()flatMap()
结果返回嵌套结构(Stream<Stream>List<List>等)返回单层扁平结构
常见用途单层对象转换嵌套结构拍平、集合嵌套处理
结果类型Stream<T[]> / Stream<List>Stream<T>
示例转换"A B" → ["A", "B"][["A", "B"], ["C", "D"]] → ["A", "B", "C", "D"]

🔥 4. 高阶实战场景

🎯 4.1. 嵌套集合扁平化

List<List<Integer>> numbers = List.of(List.of(1, 2, 3),List.of(4, 5, 6),List.of(7, 8, 9)
);List<Integer> flatList = numbers.stream().flatMap(List::stream).collect(Collectors.toList());System.out.println(flatList);
// 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]

🚀 4.2. 字符串拆分

假设我们有一组句子,想拆成单词:

List<String> sentences = List.of("Java is cool", "Stream API is powerful");List<String> words = sentences.stream().flatMap(s -> Arrays.stream(s.split(" "))).collect(Collectors.toList());System.out.println(words);
// 输出: [Java, is, cool, Stream, API, is, powerful]

🔥 4.3. 模拟 SQL JOIN

我们模拟多表连接(类似 SQL 的笛卡尔积):

List<String> names = List.of("Tom", "Jerry", "Mike");
List<String> hobbies = List.of("Coding", "Gaming", "Reading");List<String> results = names.stream().flatMap(name -> hobbies.stream().map(hobby -> name + " loves " + hobby)).collect(Collectors.toList());results.forEach(System.out::println);

输出

Tom loves Coding
Tom loves Gaming
Tom loves Reading
Jerry loves Coding
Jerry loves Gaming
Jerry loves Reading
Mike loves Coding
Mike loves Gaming
Mike loves Reading

🔥 5. Optional 配合 flatMap()

Optional 也有 flatMap()!特别适合处理嵌套 Optional:

Optional<String> optionalName = Optional.of("Java");Optional<String> upperName = optionalName.flatMap(name -> Optional.of(name.toUpperCase()));System.out.println(upperName.orElse("No Name"));
// 输出: JAVA

如果用 map()

Optional<Optional<String>> nestedOptional = optionalName.map(name -> Optional.of(name.toUpperCase()));
System.out.println(nestedOptional);
// 输出: Optional[Optional[JAVA]]  (嵌套了两层)

🎉 6. 常见坑 & 注意事项

1️⃣ 避免空指针

如果 flatMap() 操作的是嵌套集合,务必确保子集合不为 null

List<List<String>> data = List.of(List.of("Java", "Python"),null // ❗️注意这里有null
);List<String> result = data.stream().filter(Objects::nonNull) // 先过滤掉null.flatMap(list -> list == null ? Stream.empty() : list.stream()).collect(Collectors.toList());System.out.println(result);

2️⃣ 性能考虑

flatMap() 频繁拍平大数据集合时性能可能受影响,考虑分批次处理,或者用 parallelStream()


3️⃣ 嵌套层级太多

如果嵌套层次太多(List<List<List<T>>>),可以链式多次 flatMap()

List<List<List<String>>> deepNestedList = List.of(List.of(List.of("A", "B"), List.of("C")),List.of(List.of("D", "E"))
);List<String> flatResult = deepNestedList.stream().flatMap(List::stream).flatMap(List::stream).collect(Collectors.toList());System.out.println(flatResult);
// 输出: [A, B, C, D, E]

🎁 7. 终极总结

特点map()flatMap()
转换关系一对一转换一对多(Stream 扁平化)
结果类型Stream<Stream<T>>Stream<T>
常用场景数据转换,简单映射嵌套集合、字符串拆解
Optional 嵌套处理返回嵌套 Optional解开嵌套 Optional


🌟 总结

通过本文的学习,我们深入了解了 flatMap() 在 Java Stream 中的强大功能。它不仅能够处理多层嵌套数据、拆分字符串、模拟 SQL JOIN,更能让你的代码更加简洁优雅,避免冗余的嵌套结构。

无论你是数据处理,还是解决复杂的集合操作,掌握 flatMap() 都将是你提升编码能力的关键一步。希望通过本文,大家能够更高效地利用这个工具,优化自己的代码结构,让代码不仅“能用”,更要“好用”。

如果你在学习过程中有任何疑问,或者有更多 flatMap() 的应用场景,欢迎在评论区留言,我们一起讨论!别忘了点赞收藏分享给更多需要的朋友哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/72994.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(C语言)理解 回调函数 和 qsort函数

一. 回调函数 1. 什么是回调函数&#xff1f; 回调函数&#xff08;Callback Function&#xff09;是通过 函数指针 调用的函数。其本质是&#xff1a; 将函数作为参数传递给另一个函数&#xff0c;并在特定条件下被调用&#xff0c;实现 反向控制。 2. 回调函数的使用 回调函…

vscode记录

vs code 下载安装&#xff0c;git 配置&#xff0c;插件安装_vscode安装git插件-CSDN博客 手把手教你在VS Code中使用 Git_vscode如何输入git命令-CSDN博客 VS Code | 如何快速重启VS Code&#xff1f;_vscode 怎么一键全部重启-CSDN博客 1&#xff0c;安装插件与git集成 2&am…

唯品会商品详情页架构设计与实现:高并发场景下的技术实践‌

引言 唯品会作为国内领先的电商平台&#xff0c;其商品详情页需要应对海量用户的高并发访问&#xff0c;同时保证低延迟和高可用性。本文将从架构设计、数据库优化、缓存策略、前端渲染等方面&#xff0c;结合代码示例&#xff0c;深入解析唯品会商品详情页的技术实现。 一、…

大数据学习(80)-数仓分层

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

数智读书笔记系列021《大数据医疗》:探索医疗行业的智能变革

一、书籍介绍 《大数据医疗》由徐曼、沈江、余海燕合著&#xff0c;由机械工业出版社出版 。徐曼是南开大学商学院副教授&#xff0c;在大数据驱动的智能决策研究领域颇有建树&#xff0c;尤其在大数据驱动的医疗与健康决策方面有着深入研究&#xff0c;曾获天津优秀博士论文、…

SpringSecurity——前后端分离登录认证

SpringSecurity——前后端分离登录认证的整个过程 前端&#xff1a; 使用Axios向后端发送请求 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>登录</title><script src"https://cdn…

qt下载和安装教程国内源下载地址

qt不断在更新中&#xff0c;目前qt6日渐成熟&#xff0c;先前我们到官方下载或者国内镜像直接可以下载到exe文件安装&#xff0c;但是最近几年qt官方似乎在逐渐关闭旧版本下载通道&#xff0c;列为不推荐下载。但是qt5以其广泛使用和稳定性&#xff0c;以及积累大量代码使得qt5…

Mysql架构理论部分

Mysql架构是什么&#xff1f;实际可以理解为执行一条sql语句所要经历的阶段有哪些&#xff01; 1.连接层 &#xff08;1&#xff09;客户端发起连接 客户端通过TCP/IP、Unix Socket或命名管道等方式向Mysql服务器发起链接请求 想要了解tcp与udp的区别&#xff0c;可以参考这…

架构师面试(十九):IM 架构

问题 IM 系统从架构模式上包括 【介绍人模式】和 【代理人模式】。介绍人模式也叫直连模式&#xff0c;消息收发不需要服务端的参与&#xff0c;即客户端之间直连的方式&#xff1b;代理人模式也叫中转模式&#xff0c;消息收发需要服务端进行中转。 下面关于这两类模式描述的…

【服务器】RAID0、RAID1、RAID5、RAID6、RAID10异同与应用

目录 ​编辑 一、RAID概述 1.1 磁盘阵列简介 1.2 功能 二、RAID级别 2.1 RAID 0&#xff08;不含校验与冗余的条带存储&#xff09; 2.2 RAID1&#xff08;不含校验的镜像存储&#xff09; 2.3 RAID 5 &#xff08;数据块级别的分布式校验条带存储&#xff09; 4、RAI…

MySQL身份验证的auth_socket插件

在Ubuntu 20.04 LTS上&#xff0c;MySQL 8.0默认使用auth_socket插件进行身份验证&#xff0c;可能存在意想不到的情况。 一、auth_socket插件 在使用sudo mysql或通过sudo切换用户后执行任何MySQL命令时&#xff0c;不需要输入密码或错误密码都可以正常登入mysql数据库&…

小程序开发中的用户反馈收集与分析

我们在开发小程序的过程中根据开发过程中的代码及业务场景,以下是针对需求管理系统的用户反馈收集与分析方案设计: 需求管理系统用户反馈收集与分析方案 一、反馈数据模型设计 // 新增Feedback模型(app/admin/model/Feedback.php) namespace app\admin\model; use think\…

python关键字汇总

文章目录 1. 变量与类型相关2. 控制流相关3. 函数与类相关4. 异常处理相关5. 模块相关6. 其他 在 Python 3 里有 35 个关键字&#xff0c;它们各自具备特定的用途与意义 1. 变量与类型相关 True、False 意义&#xff1a;布尔类型的常量&#xff0c;分别代表逻辑真与逻辑假。示…

使用Python在Word中创建、读取和删除列表 - 详解

目录 工具与设置 Python在Word中创建列表 使用默认样式创建有序&#xff08;编号&#xff09;列表 使用默认样式创建无序&#xff08;项目符号&#xff09;列表 创建多级列表 使用自定义样式创建列表 Python读取Word中的列表 Python从Word中删除列表 在Word中&#xff…

软考-软件设计师-计算机网络

一、七层模型 中继器&#xff1a;信号会随着距离的增加而逐渐衰减&#xff0c;中继器可以接受一端的信息再将其原封不动的发给另一端&#xff0c;起到延长传输距离的作用&#xff1b; 集线器&#xff1a;多端口的中继器&#xff0c;所有端口公用一个冲突域&#xff1b; 网桥&…

关于Flask框架30道面试题及解析

文章目录 基础概念1. 什么是Flask?其核心特性是什么?2. Flask和Django的主要区别?3. 解释Flask中的“路由”概念。如何定义动态路由?核心组件4. Flask的请求上下文(Request Context)和应用上下文(Application Context)有什么区别?5. 如何访问请求参数?POST和GET方法的…

C++20 中 `constexpr` 的强大扩展:算法、工具与复数库的变革

文章目录 一、constexpr 在 <algorithm> 中的应用1. 编译时排序2. 编译时查找 二、constexpr 在 <utility> 中的应用1. 编译时交换2. 编译时条件交换 三、constexpr 在 <complex> 中的应用1. 编译时复数运算 四、总结 C20 对 constexpr 的增强是其最引人注目…

【ELK】节省存储 之 压缩存储方式调整

目录 集群版本&#xff1a; 7.17.6 解释几个概念&#xff1a; 段&#xff08;Segment&#xff09; 合并(Merge) 索引设置&#xff1a; 压缩方式(index.codec)&#xff1a; 测试设置前提条件 对比 在创建的时候指定压缩类型&#xff08;index.codec&#xff09; 对比 在…

conda create之后,以前的conda env list 只能看到环境路径 没有环境名称了

1.命令 conda env list 看到的显示如下&#xff1a; 左边这列的"base"&#xff0c;指向的路径和其它环境变量安装的路径不一致。 这时需要通过"activate [anaconda的环境路径]"和"source activate"回到anaconda&#xff1a; 2.执行切换命令 …

夸克网盘任务脚本——进阶自动版

脚本是用于自动管理和更新夸克云盘(Quark Cloud Drive)上的文件和目录的Python脚本。其主要功能包括自动下载、更新、重命名、删除文件和文件夹,以及处理和发送通知,可以在特定的时间间隔内运行,根据配置文件进行操作。 主要功能 1. Quark 类: __init__:初始化类,设置…