用于嵌套集合的 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 5flatMap 与 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 反馈 — 无需本地设置。
此课程中的所有课时
- 用于嵌套集合的 flatMap
- 并行流:性能与陷阱
- Spliterator:为并行处理进行拆分
- 使用 iterate 和 generate 创建无限流