0
点赞
收藏
分享

微信扫一扫

flatMap 详细解析 Java 8 Stream API 中的 flatMap 方法

半夜放水 01-16 09:00 阅读 6

在 Java 8 中,Stream API 提供了多种操作来处理集合数据,其中 flatMap

1. flatMap 的作用

flatMap 方法与 map 方法类似,都是将流中的每个元素映射成一个新的元素。然而,flatMapmap 的关键区别在于它能够将每个元素映射为一个新的流,而不仅仅是一个单一的值。然后,flatMap 会将所有的流合并成一个扁平的流。

简而言之:

  • map 将每个元素转换为一个值(例如:从一个字符串转换为一个整数)。
  • flatMap 将每个元素转换为一个流(例如:将一个集合转换为一个流),然后将这些流合并成一个扁平的流。

2. flatMap 方法签名

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

  • T 是输入流中元素的类型。
  • R 是输出流中元素的类型。
  • mapper 是一个函数,它将输入流中的每个元素(类型 T)映射成一个流(Stream<R>)。该流的元素类型是 R

3. 使用场景

flatMap 常见的使用场景有:

  • 处理包含多个元素的集合,将其转换为单一的流。
  • 从嵌套的数据结构(如 List<List<T>>)中提取元素。
  • 将一个对象的多个属性转换为流。

4. 示例

4.1 基本示例:从一个列表中展开多个值

假设我们有一个包含多个字符串的列表,我们想要将每个字符串拆分成字符,并生成一个扁平的流。

import java.util.Arrays;
import java.util.List;

public class FlatMapExample {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("hello", "world", "java");

        words.stream()
             .flatMap(word -> Arrays.stream(word.split("")))
             .forEach(System.out::println);
    }
}

输出:

h
e
l
l
o
w
o
r
l
d
j
a
v
a

在这个例子中:

  • flatMap(word -> Arrays.stream(word.split(""))):将每个字符串 word 使用 split 拆分成字符数组,然后转换为流 Stream<String>
  • flatMap 会将这些字符数组流合并为一个扁平的流(一个 Stream<String>)。
  • 最终我们获得了所有单个字符的流。

4.2 示例:从 List<List<Integer>> 展平为一个流

假设我们有一个 List<List<Integer>>,我们希望将嵌套的列表展开成一个单一的流。

import java.util.Arrays;
import java.util.List;

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

        listOfLists.stream()
                   .flatMap(List::stream)
                   .forEach(System.out::println);
    }
}

输出:

1
2
3
4
5
6
7
8

在这个例子中:

  • flatMap(List::stream) 将每个嵌套的列表(List<Integer>)转换为流(Stream<Integer>)。
  • flatMap 会将这些流扁平化成一个单一的流 Stream<Integer>,然后打印出所有的整数。

4.3 示例:从多个文件中读取内容并展开

假设你有多个文件,每个文件包含多行数据,你想将所有文件的内容合并为一个流。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

public class FlatMapExample {
    public static void main(String[] args) throws IOException {
        List<String> fileNames = Arrays.asList("file1.txt", "file2.txt", "file3.txt");

        fileNames.stream()
                 .flatMap(file -> {
                     try {
                         return Files.lines(Paths.get(file));
                     } catch (IOException e) {
                         e.printStackTrace();
                         return Stream.empty(); // 如果有异常,则返回一个空的流
                     }
                 })
                 .forEach(System.out::println);
    }
}

在这个例子中:

  • Files.lines(Paths.get(file)) 返回一个文件的每一行构成的流(Stream<String>)。
  • flatMap 会将所有文件的行流合并成一个单一的流,然后输出所有的行。

5. flatMapmap 的区别

mapflatMap 的行为非常相似,但是它们有一个显著的区别:

  • map:对于每个输入元素,返回一个新的元素。
  • 如果你使用 map 对一个 Stream<String> 进行操作,将每个字符串转换为一个字符数组(例如:word.split("")),返回的将是 Stream<String[]>(一个包含多个字符数组的流)。
  • flatMap:对于每个输入元素,返回一个流,然后将这些流合并成一个扁平的流。
  • 如果你使用 flatMap 对一个 Stream<String> 进行操作,将每个字符串转换为字符流,返回的将是 Stream<String>(一个扁平化的流,包含所有的字符)。

例如:

List<String> words = Arrays.asList("hello", "world");

// 使用 map
words.stream()
     .map(word -> word.split("")) // 返回一个 Stream<String[]>
     .forEach(arr -> System.out.println(Arrays.toString(arr)));

// 使用 flatMap
words.stream()
     .flatMap(word -> Arrays.stream(word.split(""))) // 返回一个扁平化的 Stream<String>
     .forEach(System.out::println);

6. 常见用法总结

  • flatMap 主要用于处理嵌套结构,如 List<List<T>> 或者流中嵌套流的情况。
  • map
  • flatMap 可以将嵌套的结构“展平”,使得元素以一个扁平的流展现。

7. 总结

  • flatMap
  • 它通常用于处理嵌套结构的数据,比如将 List<List<T>> 转换为一个单一的流 Stream<T>
  • 通过正确使用 flatMap,你可以在处理复杂数据时,获得更高效、清晰的代码。
举报

相关推荐

0 条评论