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 MapInstance {
public static void main(String[] args) {
// 示例1:字符串转大写
List<String> termList = Arrays.asList("hello", "world");
List<String> upperCaseTerms = termList.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperCaseTerms); // [HELLO, WORLD]
// 示例2:提取对象属性
class UserInfo {
String username;
UserInfo(String username) { this.username = username; }
String getUserName() { return username; }
}
List<UserInfo> userSet = Arrays.asList(
new UserInfo("Alice"),
new UserInfo("Bob")
);
List<String> userNames = userSet.stream()
.map(UserInfo::getUserName)
.collect(Collectors.toList());
System.out.println(userNames); // [Alice, Bob]
}
}
三、flatMap()方法详解
1. 基础功能
把每个元素转换成一个流,然后将所有的流合并成一个单一的流
2. 典型应用场景
- 处理嵌套的集合结构
- 将字符串拆分成多个元素
- 合并多个流
3. 示例代码
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FlatMapInstance {
public static void main(String[] args) {
// 示例1:展开嵌套集合
List<List<String>> nestedData = Arrays.asList(
Arrays.asList("Java", "Python"),
Arrays.asList("C++", "Go"),
Arrays.asList("JavaScript", "TypeScript")
);
List<String> languageList = nestedData.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(languageList);
// [Java, Python, C++, Go, JavaScript, TypeScript]
// 示例2:拆分字符串为单词
List<String> sentenceList = Arrays.asList(
"Hello World",
"Java Stream API"
);
List<String> wordList = sentenceList.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.collect(Collectors.toList());
System.out.println(wordList);
// [Hello, World, Java, Stream, API]
}
}
四、对比应用案例
场景:学生选课数据处理
import java.util.*;
import java.util.stream.*;
class StudentInfo {
String studentName;
List<String> selectedCourses;
StudentInfo(String studentName, List<String> selectedCourses) {
this.studentName = studentName;
this.selectedCourses = selectedCourses;
}
List<String> getStudentCourses() { return selectedCourses; }
}
public class CompareUsage {
public static void main(String[] args) {
List<StudentInfo> studentList = Arrays.asList(
new StudentInfo("Alice", Arrays.asList("Math", "Physics")),
new StudentInfo("Bob", Arrays.asList("History", "Art"))
);
// 错误用法:map处理嵌套集合
List<List<String>> wrongOutcome = studentList.stream()
.map(StudentInfo::getStudentCourses)
.collect(Collectors.toList());
System.out.println("错误结果:" + wrongOutcome);
// [[Math, Physics], [History, Art]]
// 正确用法:flatMap展开嵌套集合
List<String> rightOutcome = studentList.stream()
.flatMap(student -> student.getStudentCourses().stream())
.collect(Collectors.toList());
System.out.println("正确结果:" + rightOutcome);
// [Math, Physics, History, Art]
// 综合应用:统计所有课程数量
long courseTotal = studentList.stream()
.flatMap(student -> student.getStudentCourses().stream())
.count();
System.out.println("总课程数:" + courseTotal); // 4
}
}
五、常见问题解答
Q1:什么时候该用flatMap?
当遇到以下情况时考虑使用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>>> deepNestedData = ...;
deepNestedData.stream()
.flatMap(List::stream) // 展开第一层
.flatMap(List::stream) // 展开第二层
.collect(...);
六、总结对比
操作 | 输入元素 | 输出元素数量 | 最终结果结构 |
---|---|---|---|
map |
单个元素 | 1个新元素 | 保持原流的结构 |
flatMap |
单个元素 | 0-N个新元素 | 合并成单一流的结构 |
选择准则:
- 需要对单个元素进行简单转换 → 使用map()
- 需要展开嵌套结构/生成多个元素 → 使用flatMap()
以上代码均可直接在Java 8及以上环境中运行,建议在IDE中实际运行测试以加深理解。
文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/12646.html