Java Stream中map与flatMap对比教程
一、核心区别对比
方法 | 输入类型 | 输出类型 | 适用场景 | 转换关系 |
---|---|---|---|---|
map() | Function<T,R> | Stream<R> | 元素的一对一转换 | 1:1 |
flatMap() | Function<T,Stream<R>> | Stream<R> | 元素的一对多转换并合并 | 1:N |
二、map()方法详解
1. 基本功能
将流中的每个元素转换为另一个对象
2. 典型应用场景
- 类型转换
- 提取对象属性
- 数值计算
3. 示例代码
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MapExample {
public static void main(String[] args) {
// 示例1:字符串转大写
List<String> words = Arrays.asList("hello", "world");
List<String> upperCaseWords = words.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperCaseWords); // [HELLO, WORLD]
// 示例2:提取对象属性
class User {
String name;
User(String name) { this.name = name; }
String getName() { return name; }
}
List<User> users = Arrays.asList(
new User("Alice"),
new User("Bob")
);
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
System.out.println(names); // [Alice, Bob]
}
}
三、flatMap()方法详解
1. 基本功能
将每个元素转换为流,然后将所有流合并为一个流
2. 典型应用场景
- 处理嵌套集合
- 拆分字符串为多个元素
- 合并多个流
3. 示例代码
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FlatMapExample {
public static void main(String[] args) {
// 示例1:展开嵌套集合
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("Java", "Python"),
Arrays.asList("C++", "Go"),
Arrays.asList("JavaScript", "TypeScript")
);
List<String> languages = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(languages);
// [Java, Python, C++, Go, JavaScript, TypeScript]
// 示例2:拆分字符串为单词
List<String> sentences = Arrays.asList(
"Hello World",
"Java Stream API"
);
List<String> words = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.collect(Collectors.toList());
System.out.println(words);
// [Hello, World, Java, Stream, API]
}
}
四、对比使用案例
场景:学生选课数据处理
import java.util.*;
import java.util.stream.*;
class Student {
String name;
List<String> courses;
Student(String name, List<String> courses) {
this.name = name;
this.courses = courses;
}
List<String> getCourses() { return courses; }
}
public class CompareExample {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Alice", Arrays.asList("Math", "Physics")),
new Student("Bob", Arrays.asList("History", "Art"))
);
// 错误用法:map处理嵌套集合
List<List<String>> wrongResult = students.stream()
.map(Student::getCourses)
.collect(Collectors.toList());
System.out.println("错误结果:" + wrongResult);
// [[Math, Physics], [History, Art]]
// 正确用法:flatMap展开嵌套集合
List<String> correctResult = students.stream()
.flatMap(student -> student.getCourses().stream())
.collect(Collectors.toList());
System.out.println("正确结果:" + correctResult);
// [Math, Physics, History, Art]
// 综合应用:统计所有课程数量
long courseCount = students.stream()
.flatMap(student -> student.getCourses().stream())
.count();
System.out.println("总课程数:" + courseCount); // 4
}
}
五、常见问题解答
Q1:什么时候该用flatMap?
当需要处理以下结构时:
List<List<T>>
→List<T>
Stream<Stream<R>>
→Stream<R>
- 需要拆分元素为多个子元素时
Q2:可以组合使用map和flatMap吗?
可以,常见组合方式:
list.stream()
.map(...) // 初步转换
.flatMap(...) // 展开处理
.collect(...)
Q3:如何处理多层嵌套?
使用多次flatMap:
List<List<List<String>>> deepNested = ...;
deepNested.stream()
.flatMap(List::stream) // 展开第一层
.flatMap(List::stream) // 展开第二层
.collect(...);
六、总结对比
操作 | 输入元素 | 输出元素数量 | 最终结果结构 |
---|---|---|---|
map | 单个元素 | 1个新元素 | 保持原流结构 |
flatMap | 单个元素 | 0-N个新元素 | 合并为单一流结构 |
选择原则:
- 需要简单转换单个元素 → 使用
map()
- 需要展开嵌套结构/生成多个元素 → 使用
flatMap()
以上代码均可直接复制到Java 8+环境中运行,建议在IDE中实际测试观察输出结果,以加深理解。