Java 使用flatMap与map方法,用户希望以某种方式转换流中的元素,但不确定该使用 map
还是 flatMap
方法。如果需要将每个元素转换为一个值,则使用 Stream.map
方法;如果需要将每个元素转换为多个值,且需要将生成的流“展平”,则使用 Stream.flatMap
方法。
Java 使用flatMap与map方法 问题描述
用户希望以某种方式转换流中的元素,但不确定该使用 map
还是 flatMap
方法。
Java 使用flatMap与map方法 解决方案
如果需要将每个元素转换为一个值,则使用 Stream.map
方法;如果需要将每个元素转换为多个值,且需要将生成的流“展平”,则使用 Stream.flatMap
方法。
Java 使用flatMap与map方法 具体实例
map
和 flatMap
方法均传入 Function
作为参数。map
方法的签名如下:
Function
传入一个输入,并将其转换为一个输出。map
方法则将一个 T
类型的输入转换为一个 R
类型的输出。
我们创建一个由顾客名和 Order
集合构成的 Customer
类。为简单起见,Order
类只包含一个整数 ID。例 3-54 展示了 Customer
类和 Order
类。
例 3-54 一对多关系
接下来,我们创建若干新顾客并添加一些订单,如例 3-55 所示。
例 3-55 客户与订单示例
当输入参数和输出类型之间存在一一对应的关系时,将执行 map
操作。可以将顾客映射到他们的姓名并打印,如例 3-56 所示。
例 3-56 将顾客映射到他们的姓名
❶ Stream<Customer>
❷ Stream<String>
❸ 谢里登、伊万诺娃、加里波第
如果将顾客映射到订单而不是他们的姓名,就得到了一个集合的集合,如例 3-57 所示。
例 3-57 将顾客映射到订单
❶ Stream<List<Order>>
❷ [Order{id=1}, Order{id=2}, Order{id=3}], [Order{id=4}, Order{id=5}], []
❸ Stream<Stream<Order>>
map
操作的结果为 Stream<List<Order>>
,其最后一个列表为空。如果在订单列表中调用 stream
方法,则结果为 Stream<Stream<Order>>
,其最后一个内部流(inner stream)为空流。
flatMap
方法的作用就在于此,其签名如下:
对于每个泛型参数 T
,函数生成的是 Stream<R>
而不仅仅是 R
。之后,flatMap
方法从各个流中删除每个元素并将它们添加到输出,从而“展平”生成的流。
flatMap
方法的Function
参数传入一个泛型输入参数,但生成的输出类型为Stream
。
flatMap
方法的应用如例 3-58 所示。
例 3-58 对顾客订单应用
flatMap
方法
❶ Stream<Customer>
❷ Stream<Order>
❸ Order{id=1}, Order{id=2}, Order{id=3}, Order{id=4}, Order{id=5}
flatMap
操作的结果为 Stream<Order>
。由于它已被“展平”,无须再担心嵌套流(nested stream)。
与 flatMap
方法有关的两个重要概念应予注意:
- 方法参数
Function
产生一个输出值流; -
生成的元素被“展平”为一个新的流。
将上述两点谨记在心,就能体会到 flatMap
方法的有用之处。
最后需要指出的是,Java 8 引入的 Optional
类同样定义了 map
和 flatMap
方法,详细讨论请参见范例Optional.flatMap与Optional.map方法和范例Optional的映射。