0Pricing
Java Academy · 课时

用于嵌套集合的 flatMap

使用 flatMap 展平嵌套列表、Optional 链和文件行结构

用于嵌套集合的 flatMap 是 CoddyKit 上的免费 Java Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

嵌套集合问题

当流中的每个元素都映射到另一个集合时,map 会得到一个 Stream<List<T>>。flatMap 会将内部流合并为一个扁平的 Stream<T>。

List<List<Integer>> nested = List.of(List.of(1,2), List.of(3,4), List.of(5));
// With map:
Stream<List<Integer>> s = nested.stream().map(l -> l); // Stream<List<Integer>>
// With flatMap:
Stream<Integer> flat = nested.stream().flatMap(List::stream); // Stream<Integer>
flat.forEach(System.out::println); // 1 2 3 4 5

flatMap 与 map

map(f) 将 f 应用于每个元素,并封装结果。flatMap(f) 将 f 应用于每个元素,得到一个流,然后把所有这些流连接成一个流。

// map: List<String> -> Stream<Stream<Character>>
Stream<Stream<Character>> nested = List.of("hi","bye").stream()
    .map(s -> s.chars().mapToObj(c -> (char)c));
// flatMap: List<String> -> Stream<Character>
Stream<Character> flat = List.of("hi","bye").stream()
    .flatMap(s -> s.chars().mapToObj(c -> (char)c));

扁平化订单和项目

经典用法:每个订单都有一个项目列表。获取包含所有订单中全部项目的扁平流。

List<String> allItems = orders.stream()
    .flatMap(order -> order.getItems().stream())
    .collect(Collectors.toList());
System.out.println(allItems);

flatMap 与 Optional

在 Optional 上使用 stream()(Java 9 及更高版本),将其转换为包含 0 个或 1 个元素的流。然后,flatMap 会将 Stream<Optional<T>> 压平为 Stream<T>。

List<Optional<String>> maybes = List.of(Optional.of("a"), Optional.empty(), Optional.of("c"));
List<String> values = maybes.stream()
    .flatMap(Optional::stream)  // Java 9+
    .collect(Collectors.toList());
System.out.println(values); // [a, c]

从多个文件读取所有行

flatMap 可以轻松地将文件列表中的所有行连接为一个流,而无需使用嵌套循环。

List<Path> files = List.of(Path.of("a.txt"), Path.of("b.txt"));
List<String> allLines = files.stream()
    .flatMap(p -> {
        try { return Files.lines(p); }
        catch (IOException e) { return Stream.empty(); }
    })
    .collect(Collectors.toList());

将字符串拆分为单词

将每个句子拆分为单词,并将所有单词压平为一个流,以统计单词频率。

List<String> sentences = List.of("hello world", "java streams rock");
Map<String, Long> freq = sentences.stream()
    .flatMap(s -> Arrays.stream(s.split("\\s+")))
    .collect(Collectors.groupingBy(w -> w, Collectors.counting()));
System.out.println(freq);

flatMap 与 Map.entrySet

将从类别到项目列表的映射压平为包含所有项目的流。

Map<String, List<String>> catalog = Map.of(
    "fruit", List.of("apple","banana"),
    "veg",   List.of("carrot","pea"));
List<String> all = catalog.values().stream()
    .flatMap(List::stream)
    .sorted()
    .collect(Collectors.toList());
System.out.println(all); // [apple, banana, carrot, pea]

避免 flatMap 中的 NullPointerException

如果函数可能返回 null 而不是流,请使用空值检查,或返回 Stream.empty(),以避免 NullPointerException。

departments.stream()
    .flatMap(dept -> dept.getEmployees() == null
        ? Stream.empty()
        : dept.getEmployees().stream())
    .forEach(System.out::println);

使用 flatMap 统计不重复单词

组合使用 flatMap、distinct 和 count,即可简洁地处理数据。

long distinctWords = sentences.stream()
    .flatMap(s -> Arrays.stream(s.toLowerCase().split("[^a-z]+")))
    .filter(w -> !w.isEmpty())
    .distinct()
    .count();
System.out.println("Distinct: " + distinctWords);

使用 flatMapToInt 处理基本类型流

使用 flatMapToInt、flatMapToLong 和 flatMapToDouble,在压平为基本类型流时避免装箱。

int totalQuantity = orders.stream()
    .flatMapToInt(order -> order.getItems().stream().mapToInt(Item::getQuantity))
    .sum();
System.out.println("Total qty: " + totalQuantity);

性能说明

每次调用 flatMap 都会增加一层流。对于包含大量小型内部集合的超大型数据集,可以考虑迭代方式或使用 Spliterator,以减少对象创建开销。

快速检查

flatMap 与 map 的不同之处是什么?

回顾

flatMap 会将每个元素转换为一个流,并将所有流合并为一个流。可以使用它来扁平化嵌套集合、串联 Optional、拆分字符串以及读取多个文件。使用 flatMapToInt 可以避免装箱。

常见问题解答

「用于嵌套集合的 flatMap」课时是免费的吗?

是的 — 「用于嵌套集合的 flatMap」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「用于嵌套集合的 flatMap」这节课中我会学到什么?

使用 flatMap 展平嵌套列表、Optional 链和文件行结构 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「用于嵌套集合的 flatMap」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 用于嵌套集合的 flatMap
  2. 并行流:性能与陷阱
  3. Spliterator:为并行处理进行拆分
  4. 使用 iterate 和 generate 创建无限流
← 返回 Java Academy