map:一个元素 → 一个流元素(一对一) flatMap:一个元素 → 一个 Stream 流,然后自动把所有流拆开合并成一个大流(一对多、摊平嵌套)
一句话:
map得到Stream<集合>,flatMap得到Stream<集合里面的元素>
场景 1:最简单案例 — List<List<String>> 二维集合摊平
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FlatMapDemo {
public static void main(String[] args) {
// 二维列表:嵌套集合
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("苹果", "香蕉"),
Arrays.asList("橘子", "葡萄"),
Arrays.asList("芒果")
);
// ✅ map 写法:Stream<List<String>>,得到的还是嵌套,不是我们想要的
List<List<String>> mapResult = nestedList.stream()
.map(subList -> subList)
.collect(Collectors.toList());
System.out.println("map结果:" + mapResult);
// map结果:[[苹果, 香蕉], [橘子, 葡萄], [芒果]]
// ✅ flatMap:把子集合转成Stream,全部摊平成一维流
List<String> flatResult = nestedList.stream()
.flatMap(subList -> subList.stream()) // 每个子list转成流,合并
.collect(Collectors.toList());
System.out.println("flatMap摊平后:" + flatResult);
// flatMap摊平后:[苹果, 香蕉, 橘子, 葡萄, 芒果]
}
}
场景 2:开发高频:实体里面包含子集合(最常用!)
比如:一个订单 Order,里面有多个订单项 OrderItem
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Data
@AllArgsConstructor
class Order {
private Long orderId;
private List<OrderItem> itemList; // 一个订单包含多个订单项
}
@Data
@AllArgsConstructor
class OrderItem {
private String productName;
private Integer num;
}
public class FlatMapOrderDemo {
public static void main(String[] args) {
List<Order> orderList = Arrays.asList(
new Order(1001L, Arrays.asList(
new OrderItem("手机", 1),
new OrderItem("耳机", 2)
)),
new Order(1002L, Arrays.asList(
new OrderItem("电脑", 1)
))
);
// 需求:拿到【所有订单里全部商品名称】,收集成一维List
List<String> allProductNames = orderList.stream()
// order.getItemList() 是子集合,转成流,自动摊平
.flatMap(order -> order.getItemList().stream())
.map(OrderItem::getProductName)
.collect(Collectors.toList());
System.out.println(allProductNames);
// [手机, 耳机, 电脑]
}
}
如果这里用 map,得到的是
Stream<List<OrderItem>>,还是嵌套结构,没法直接拿商品名。
场景 3:字符串分割,把一句话拆成单词(经典示例)
List<String> sentences = Arrays.asList("hello world", "java stream", "flatMap test");
List<String> words = sentences.stream()
// 每一行字符串分割成字符串数组,转成Stream
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.distinct() // 去重
.collect(Collectors.toList());
System.out.println(words);
// [hello, world, java, stream, flatMap, test]
对比:
map:
.map(s -> s.split(" "))→Stream<String[]>flatMap:
.flatMap(s -> Arrays.stream(s.split(" ")))→Stream<String>
场景 4:flatMapToInt /flatMapToLong 基础类型流
如果是基本类型,避免包装类,用专门的 flatMap:
List<List<Integer>> numNest = Arrays.asList(
Arrays.asList(1,2,3),
Arrays.asList(4,5)
);
int sum = numNest.stream()
.flatMapToInt(sub -> sub.stream().mapToInt(Integer::intValue))
.sum();
System.out.println(sum); // 15
map vs flatMap 对比表
新手易错点
flatMap 的 lambda 必须返回 Stream,不能直接返回集合 / 数组 ✅
flatMap(list -> list.stream())❌flatMap(list -> list)直接返回 List,编译报错多层嵌套(三维):可以多次 flatMap 连续摊平
// List<List<List<String>>> 三层嵌套
List<String> res = threeNest.stream()
.flatMap(l2 -> l2.stream())
.flatMap(l1 -> l1.stream())
.collect(Collectors.toList());本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问