每个 Java 开发者都应该了解 FlatMap

Java 8 Streams 中的 flatMap 方法是将元素流(通常涉及嵌套或复杂结构)转换为扁平化流的强大工具。以下是每种方法的解释及实际示例。

“虽然 AI 工具协助起草了这篇文章,但通过我的专业知识,它得到了进一步的塑造和完善。”

1. flatMap (通用流)

定义:

  • flatMap 是一个中间操作。
  • 中间操作将一个流转换为另一个流,并允许进一步的流操作。
  • “flat”在 flatMap 中指的是其能够将一系列集合(例如 Stream<List<T>> )扁平化为单一的元素流( Stream<T> )。
  • 目的:将原始流中的每个元素转换为其他元素的流(一对多映射),然后将生成的流展平为单个连续流。

示例:假设你有一个订单列表,每个订单包含一个商品列表。你想要一个包含所有订单中所有商品的扁平列表。

class Order {
    private List<String> lineItems;

    public Order(List<String> lineItems) {
        this.lineItems = lineItems;
    }

    public List<String> getLineItems() {
        return lineItems;
    }
}

public class Example {
    public static void main(String[] args) {
        List<Order> orders = Arrays.asList(
            new Order(Arrays.asList("item1", "item2")),
            new Order(Arrays.asList("item3", "item4"))
        );

        // Flatten list of lineItems
        List<String> allItems = orders.stream()
            .flatMap(order -> order.getLineItems().stream())
            .collect(Collectors.toList());

        System.out.println(allItems); // [item1, item2, item3, item4]
    }
}

另一个例子

List<List<Integer>> listOfLists = Arrays.asList(
    Arrays.asList(1, 2, 3),
    Arrays.asList(4, 5),
    Arrays.asList(6, 7, 8)
);

List<Integer> flattenedList = listOfLists.stream()
    .flatMap(List::stream) // Flatten the Stream<List<Integer>> into Stream<Integer>
    .collect(Collectors.toList());

System.out.println(flattenedList); // Output: [1, 2, 3, 4, 5, 6, 7, 8]

2. flatMapToInt

定义:

  • 将原始流的每个元素转换为 IntStream ,并将这些流展平为单个 IntStream 。

示例:假设你有一个包含整数列表的列表,并且你想要一个包含所有整数的扁平流

public class Example {
    public static void main(String[] args) {
        List<List<Integer>> listOfLists = Arrays.asList(
            Arrays.asList(1, 2, 3),
            Arrays.asList(4, 5, 6)
        );

        IntStream intStream = listOfLists.stream()
            .flatMapToInt(list -> list.stream().mapToInt(Integer::intValue));

        intStream.forEach(System.out::println); // Output: 1 2 3 4 5 6
    }
}

flatMap 作为中间操作的特点:

  1. 惰性求值:与所有中间操作一样, flatMap 是惰性求值的。实际的运算仅在调用终端操作(如 collect )时发生。
  2. 结合映射与扁平化:它映射流中的元素,并将生成的嵌套结构扁平化。

3. flatMapToLong

定义:

  • 类似于 flatMapToInt ,但使用 LongStream 处理长值。

示例:将长数组流扁平化为 LongStream

public class Example {
    public static void main(String[] args) {
        List<long[]> longLists = Arrays.asList(
            new long[]{1L, 2L, 3L},
            new long[]{4L, 5L, 6L}
        );

        LongStream longStream = longLists.stream()
            .flatMapToLong(Arrays::stream);

        longStream.forEach(System.out::println); // Output: 1 2 3 4 5 6
    }
}

4. flatMapToDouble

定义:

  • 类似于 flatMapToInt ,但使用 DoubleStream 处理浮点数值。

示例:将双精度数组流扁平化为 DoubleStream

关键点

  1. 扁平化嵌套数据:
  • flatMap 方法的主要目的是将复杂结构(如列表的列表)“展平”为单一流。

2. 中间操作:

  • 所有 flatMap 方法都是中间操作,意味着它们会转换流并允许进一步处理。

3. 映射函数:

  • 传递给 flatMap 的函数必须返回一个流(例如, Stream 、 IntStream 、 LongStream 或 DoubleStream )。

4. 处理空值:

  • 如果映射函数返回 null ,则将其替换为空流以避免 NullPointerException

何时使用?

  • flatMap : 当处理嵌套集合或结构时。
  • flatMapToInt/Long/Double : 处理原始流以避免不必要的装箱/拆箱开销
请登录后发表评论

    没有回复内容