瞧高手如何用flatMap简化代码!

点击上方"程序员蜗牛g",选择"设为星标"

跟蜗牛哥一起,每天进步一点点

程序员蜗牛g

大厂程序员一枚 跟蜗牛一起 每天进步一点点

33篇原创内容

**

公众号

本篇文章将详细的介绍flatMap函数的各种场景下的使用。

假设你有一个List<List>,而你想要得到一个包含所有字符串的单一列表。大多数开发者会在这里使用flatMap,如下示例:

less 复制代码
List<List<String>> names = List.of(  List.of("张三", "李四"),  List.of("曹查理", "大卫"),  List.of("女娲", "Jerry"));// 使用流(Stream)将嵌套的列表展平为一个单一的字符串列表List<String> flattened = names.stream()  .flatMap(List::stream)  // 将每个子列表中的元素"拉平"到一个流中  .toList();  // 收集结果为一个新列表// 输出展平后的结果System.out.println(flattened);

输出结果

css 复制代码
[张三, 李四, 曹查理, 大卫, 女娲, Jerry]

这是最基础用法。我们没有得到一个Stream<List>,而是将其"扁平化"成了一个单一的Stream。**

**

使用Optional时的flatMap技巧

如果你正在使用一个可能存在也可能不存在的数据时。你可能会用 Optional 来处理这种情况。但是,如果你需要串联多个操作呢?

通常情况下,你会得到嵌套的Optional<Optional>,这看起来就很头大。而这正是flatMap大显身手的地方。如下示例:

vbnet 复制代码
public static void main(String[] args) {  Optional<String> nameOpt = Optional.of("Spring Boot3实战案例200讲");  Optional<Optional<String>> result = nameOpt      .map(FlatMapDemo2::toUpperCase); // ❌ 得到嵌套的 Optional  System.out.println(result);}public static Optional<String> toUpperCase(String s) {  if (s == null || s.isEmpty()) {      return Optional.empty();  }  return Optional.of(s.toLowerCase());}

输出结果

python 复制代码
Optional[Optional[spring boot3实战案例200讲]]

使用flatMap

vbnet 复制代码
Optional<String> nameOpt = Optional.of("Spring Boot3实战案例200讲");Optional<String> result = nameOpt.flatMap(FlatMapDemo2::toUpperCase) ;System.err.println(result) ;

输出结果

css 复制代码
Optional[spring boot3实战案例200讲]

总结:

  • map:会对结果进行包装,从而产生嵌套结构。
  • flatMap:会解开包装,保持简洁。

flatMap替代嵌套循环

嵌套循环,会损害代码的可读性,尤其是在处理多维数据时。而flatMap可以用一种更优雅的方式替代它们。

如下示例:两个列表的笛卡尔积,假设你想要生成产品及其所有颜色组合的列表。

less 复制代码
List<String> products = List.of("IPad", "IPhone", "Book");List<String> colors = List.of("黑色", "白色");List<String> result = products.stream()  .flatMap(product -> colors.stream()          .map(color -> product + " - " + color))  .collect(Collectors.toList());result.forEach(System.out::println);

输出结果

复制代码
IPad - 黑色IPad - 白色IPhone - 黑色IPhone - 白色Book - 黑色Book - 白色

如果不使用flatMap,你就得编写嵌套循环。而使用flatMap后,代码会变得清晰、简洁且具有函数式风格。**

**

flatMap处理API响应

在实际应用中,你经常需要从可能返回列表、可选字段或嵌套结构的API中获取数据。你可以使用flatMap直接转换并扁平化结果,而无需进行空值检查。

如下示例:扁平化API数据,假设有一个User类,其中包含一个返回电话号码列表的方法:

arduino 复制代码
public static void main(String[] args) {  List<User> users = List.of(      new User("Pack_xg", Arrays.asList("111", "222")),      new User("pack", Arrays.asList("333")),      new User("xg", Arrays.asList("444", "555"))      );  List<String> result = users.stream()      .flatMap(user -> user.phones().stream())      .toList() ;  System.out.println(result);}public static record User(String name, List<String> phones) {}

输出结果

csharp 复制代码
[111, 222, 333, 444, 555]

如果你用for循环实现此功能,代码会显得臃肿。而借助flatMap,只需一行代码就能完成转换。**

**

flatMap + filter:秘密武器

大多数开发者会使用filter和map,但很少将它们与flatMap结合使用。而正是这种结合能让你解锁另一层强大功能。如下示例:提取有效电子邮件地址

less 复制代码
List<List<String>> emails = List.of(    List.of("pack_xg@gmail.com", "www.qq.com"),    List.of("pack@yahoo.com"),    List.of("xg@", "xxxooo@qq.com"));List<String> result = emails.stream()    .flatMap(List::stream)    .filter(email -> email.contains("@") && email.contains("."))    .toList() ;System.out.println(result);

输出结果

perl 复制代码
[pack_xg@gmail.com, pack@yahoo.com, xxxooo@qq.com]

我们无需逐个验证嵌套列表中的元素,而是可以在一个操作链中完成扁平化、过滤和收集。

综合示例

你需要获取用户数据;每个用户都有若干订单;每个订单都包含若干产品。而你想要得到一个扁平化的列表,其中包含所有用户购买的所有产品的名称。

准备如下类:

vbnet 复制代码
//商品public record Product(String name) {}//订单public record Order(List<Product> products) {}//用户public record User(String name, List<Order> orders) {}

准备数据

sql 复制代码
List<Product> p1 = List.of(  new Product("iPhone 15"),  new Product("AirPods Pro"));List<Product> p2 = List.of(  new Product("MacBook Pro"));List<Order> o1 = List.of(  new Order(p1),  new Order(p2));User zhangsan = new User("张三", o1);List<Product> lisiProducts1 = List.of(  new Product("iPad Air"),  new Product("Apple Watch"));List<Order> o2 = List.of(    new Order(lisiProducts1));User lisi = new User("李四", o2);User wangwu = new User("王五", List.of());// 所有用户List<User> users = List.of(zhangsan, lisi, wangwu) ;

传统做法

css 复制代码
List<String> productNames = new ArrayList<>();for (User user : users) {  for (Order order : user.orders()) {    for (Product product : order.products()) {      productNames.add(product.name());    }  }}System.err.println(productNames) ;

使用flatMap

scss 复制代码
List<String> productNames = users.stream()  .flatMap(user -> user.orders().stream())  .flatMap(order -> order.products().stream())  .map(Product::name)  .toList() ;

总结:掌握flatMap不仅会让你的代码更简洁------它还会改变你的思维方式。你将不再编写那些千篇一律的循环代码。

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记 就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

相关推荐
天天摸鱼的java工程师3 小时前
Java IO 流 + MinIO:游戏玩家自定义头像上传(格式校验、压缩处理、存储管理)
java·后端
间彧3 小时前
SpringBoot中结合SimplePropertyPreFilter排除JSON敏感属性
后端
Cache技术分享3 小时前
207. Java 异常 - 访问堆栈跟踪信息
前端·后端
功能啥都不会3 小时前
MySql基本语法对照表
后端
程序员小富3 小时前
改了 Nacos 一行配置,搞崩线上支付系统!
java·后端
golang学习记3 小时前
MCP官方 Go SDK v1.0 正式发布,我立马实现了自己的MCP server
后端
知其然亦知其所以然3 小时前
面试官一开口就问:“你了解MySQL水平分区吗?”我当场差点懵了……
后端·mysql·面试
GeekAGI3 小时前
使用 curl 进行并发请求的指南:7种方法详解
后端
BingoGo3 小时前
PHP 开发者应该理解的 Linux 入门权限指南
后端·php