小易说IT 小易说IT

Java Stream的flatMap 扁平化代码演示

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 对比表

方法

函数返回值

流类型

用途

map

R

Stream<R>

一对一转换

flatMap

Stream<R>

Stream<R>

一对多,摊平嵌套

新手易错点

  1. flatMap 的 lambda 必须返回 Stream,不能直接返回集合 / 数组 ✅ flatMap(list -> list.stream()) ❌ flatMap(list -> list) 直接返回 List,编译报错

  2. 多层嵌套(三维):可以多次 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,转载请注明出处。

原文链接 https://www.yijunzhao.cc/archives/java-stream-flatmap-flattening-code-demo

欢迎访问 https://www.yijunzhao.cc/

https://www.yijunzhao.cc/