Java流对象stream的flatMap方法详解
Java流对象stream的flatMap方法是一个强大且灵活的工具,用于处理集合数据。
起源
flatMap方法起源于函数式编程的概念,并在Java 8中被引入到Stream API中。它的设计初衷是为了提供一种更简洁、更高效的方式来处理集合数据,特别是嵌套集合或复杂数据结构。
定义
flatMap方法是Java Stream API中的一个重要中间操作,它可以将流中的每个元素转换为一个新的流,并将这些流合并成一个单一的流。简单来说,flatMap方法允许你将一个流中的元素“展平”成另一个流中的多个元素。
方法签名
flatMap 方法在 Stream 接口中有两个泛型方法签名:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); <R> Stream<R> flatMapToInt(Function<? super T, ? extends IntStream> mapper); <R> Stream<R> flatMapToLong(Function<? super T, ? extends LongStream> mapper); <R> Stream<R> flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
其中,最常用的是第一个方法签名,它允许你将每个元素映射成一个 Stream<R>,然后将这些流合并成一个 Stream<R>。
原理
- 映射操作:
flatMap接受一个函数作为参数,这个函数将流中的每个元素映射成一个新的流。 - 合并操作:然后,
flatMap将这些新的流合并成一个单一的流。这个合并过程实际上是“扁平化”的,即它将多个流中的元素合并到一个流中,而不是保留流的嵌套结构。 - 惰性求值:与Stream API中的其他操作一样,
flatMap也是惰性求值的。这意味着它不会立即执行映射和合并操作,而是等到需要结果时才进行计算。
用途
flatMap方法的主要用途是处理嵌套集合或将集合中的元素展平。它常用于以下场景:
- 嵌套集合的扁平化:当你有一个包含多个子集合的集合时,你可以使用
flatMap将这些子集合中的元素合并到一个单一的集合中。 - 复杂数据结构的转换:当你需要将一个复杂的数据结构(如对象列表中的对象属性列表)转换为一个简单的数据结构(如单个列表)时,
flatMap是一个很好的选择。 - 元素的拆分与合并:在某些情况下,你可能需要将流中的每个元素拆分成多个元素,并将这些元素合并到一个新的流中。这时,
flatMap也非常有用。
使用场景示例
- 嵌套列表的扁平化:
List<List<String>> nestedList = Arrays.asList( Arrays.asList("a", "b", "c"), Arrays.asList("d", "e"), Arrays.asList("f", "g", "h", "i") ); List<String> flattenedList = nestedList.stream() .flatMap(List::stream) .collect(Collectors.toList()); System.out.println(flattenedList); // 输出: [a, b, c, d, e, f, g, h, i]
- 对象属性的提取与合并:
假设你有一个User类,其中包含一个List<String>类型的addresses属性。现在,你有一个List<User>对象,并希望提取所有用户的所有地址。
List<User> users = Arrays.asList( new User("Alice", Arrays.asList("123 Main St", "456 Oak St")), new User("Bob", Arrays.asList("789 Pine St")), new User("Charlie", Arrays.asList("101 Maple St", "202 Birch St", "303 Cedar St")) ); List<String> allAddresses = users.stream() .flatMap(user -> user.getAddresses().stream()) .collect(Collectors.toList()); System.out.println(allAddresses); // 输出: [123 Main St, 456 Oak St, 789 Pine St, 101 Maple St, 202 Birch St, 303 Cedar St]
与 map 的区别
map方法将流中的每个元素映射成一个新的元素,并返回一个新的流,但流的结构(元素的数量)保持不变。flatMap方法将流中的每个元素映射成一个新的流,然后将这些流合并成一个单一的流,因此流的结构(元素的数量)可能发生变化。
示例对比
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class MapVsFlatMap { public static void main(String[] args) { List<List<String>> listOfLists = Arrays.asList( Arrays.asList("a", "b", "c"), Arrays.asList("d", "e"), Arrays.asList("f", "g", "h", "i") ); // 使用 map 方法 List<Stream<String>> mapped = listOfLists.stream() .map(List::stream) .collect(Collectors.toList()); System.out.println(mapped); // 输出: [java.util.stream.ReferencePipeline$Head@..., java.util.stream.ReferencePipeline$Head@..., java.util.stream.ReferencePipeline$Head@...] // 使用 flatMap 方法 List<String> flatMapped = listOfLists.stream() .flatMap(List::stream) .collect(Collectors.toList()); System.out.println(flatMapped); // 输出: [a, b, c, d, e, f, g, h, i] } }
在上面的例子中,map 方法返回的是包含多个 Stream<String> 的列表,而 flatMap 方法则将这些流合并成一个单一的流。
总结
flatMap 方法在处理需要将多个流合并成一个流时非常有用。它允许你将每个元素映射成一个新的流,并将这些流扁平化为一个单一的流,从而简化了复杂的数据处理任务。
浙公网安备 33010602011771号