Java 8 中 map() 和 flatMap() 方法的区别

10 Sept 2024 | 4 分钟阅读

在 Java 8 的函数式编程领域,map()flatMap() 操作是 Stream API 的基本组成部分。这两个方法虽然名称相似,但却服务于不同的目的,理解它们的区别对于编写清晰、富有表现力且高效的代码至关重要。在本节中,我们将讨论 Java 8 中 map() 和 flatMap() 的区别

map(): 转换流中的元素

map() 操作用于转换流中的元素。它将给定的函数应用于每个元素,生成一个由转换后的元素组成的新流。

示例

在此示例中,map() 用于将流中的每个单词转换为大写。

flatMap(): 展平嵌套结构

flatMap() 操作功能更强大,主要用于处理嵌套结构,例如列表流或可选值流。它不仅转换元素,还将生成的流的流(或其他嵌套结构)展平成单个流。

示例

这里,flatMap() 用于将列表的列表展平成一个包含整数的单个列表。

Java 8 中的 map() 与 flatMap()

特性map()flatMap()
目的转换流中的元素。展平流中的嵌套结构。
转换函数 一对一转换。可以生成一个流或其他结构。
输出大小可预测(与输入大小 1:1)。可变,取决于转换。
用例一元转换。处理嵌套结构。
适用性无状态转换。有状态转换,输出可变。
性能输出大小可预测。输出大小可变,可能更复杂。

用例

map(): 一元转换

当我们想对流中的每个元素应用一对一转换时,请使用 map()。

它适用于转换函数不返回流或其他复杂结构的场景。

flatMap(): 处理嵌套结构

当处理转换函数返回一个流或我们想展平的结构时,请使用 flatMap()。

它在处理包含可选值的场景中特别有用,因为我们可以过滤掉空的可选值。

高级用例

map(): 无状态转换

map() 常用于无状态转换,其中每个元素都独立于其他元素进行转换。

flatMap(): 有状态转换

flatMap() 对于有状态转换或每个元素转换为可变数量元素的场景非常强大。

性能考虑

map(): 输出大小可预测

由于 map() 执行一对一转换,因此输出大小是可预测的,并且与输入流的大小相对应。

flatMap(): 输出大小可变

flatMap() 可以为每个输入元素生成可变数量的元素。这使其更适用于转换可能导致不同大小输出的场景。

Java map() 示例

MapExample.java

输出

Original words: [Java, is, awesome]
Uppercased words: [JAVA, IS, AWESOME]

Java flatMap() 示例

FlatMapExample.java

输出

Original list of lists: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Flattened list of integers: [1, 2, 3, 4, 5, 6, 7, 8, 9]

在 map 示例中,toUpperCase() 方法应用于流的每个元素,将其转换为大写。

在 flatMap() 示例中,flatMap() 用于将列表的列表展平成一个包含整数的单个列表。

虽然 map() 和 flatMap() 都是 Java 8 函数式编程工具箱中的重要工具,但它们服务于不同的目的。理解何时使用 map() 进行简单转换,何时利用 flatMap() 的强大功能来处理嵌套结构,是编写富有表现力且高效代码的关键。掌握这些操作,开发者就能充分利用 Java 8 及更高版本中 Stream API 的全部潜力。