Java Stream API实战大全:从入门到高阶应用
一、Stream核心概念
Java 8引入的Stream API为集合操作提供函数式编程能力:
// 传统集合操作
List<String> filteredNames = new ArrayList();
for (String name : names) {
if (name.startsWith("张")) {
filteredNames.add(name.toUpperCase());
}
}
// Stream等效实现
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("张"))
.map(String::toUpperCase)
.collect(Collectors.toList());
Stream三大特性:无存储、惰性求值、可消费性
二、Stream操作分类
操作类型 | 方法示例 | 特点 |
---|---|---|
中间操作 | filter(), map(), sorted() | 可链式调用,延迟执行 |
终端操作 | collect(), forEach(), reduce() | 触发实际计算 |
三、高阶应用场景
1. 数据分组与统计
// 按部门分组统计工资
Map<String, DoubleSummaryStatistics> stats = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.summarizingDouble(Employee::getSalary)
));
// 输出各部门平均工资
stats.forEach((dept, s) ->
System.out.println(dept + "平均工资:" + s.getAverage()));
2. 多级数据处理
// 获取所有订单中的唯一产品列表
List<Product> uniqueProducts = orders.stream()
.flatMap(order -> order.getItems().stream())
.map(OrderItem::getProduct)
.distinct()
.collect(Collectors.toList());
四、性能优化技巧
- 优先使用基本类型流:IntStream/LongStream避免装箱开销
- 短路操作:findFirst/anyMatch提前终止流
- 并行流谨慎使用:数据量大且无状态操作时启用
- 方法引用优化:替代简单lambda表达式
// 并行流示例 (适合CPU密集型)
long count = largeList.parallelStream()
.filter(item -> item.getValue() > 100)
.count();
// 方法引用优化
List<String> names = persons.stream()
.map(Person::getName) // 替代 p -> p.getName()
.collect(Collectors.toList());
五、自定义Collector实战
实现字符串拼接Collector:
// 自定义字符串拼接Collector
Collector<String, StringBuilder, String> concatenator =
Collector.of(
StringBuilder::new, // supplier
StringBuilder::append, // accumulator
(sb1, sb2) -> sb1.append(sb2), // combiner
StringBuilder::toString // finisher
);
// 使用示例
String result = Stream.of("A", "B", "C")
.collect(concatenator); // 输出"ABC"
六、与传统循环性能对比
操作 | 10万数据(ms) | 100万数据(ms) |
---|---|---|
传统for循环 | 25 | 180 |
顺序Stream | 28 | 195 |
并行Stream | 15 | 90 |
测试环境:JDK 17/8核CPU
七、实际应用案例
1. 数据清洗转换
// CSV数据清洗管道
List<Product> validProducts = rawData.stream()
.skip(1) // 跳过标题行
.map(line -> line.split(","))
.filter(values -> values.length == 5)
.map(values -> new Product(
values[0].trim(),
Double.parseDouble(values[1]),
Integer.parseInt(values[2]),
LocalDate.parse(values[3]),
ProductCategory.valueOf(values[4])
))
.filter(p -> p.getStock() > 0)
.collect(Collectors.toList());
2. 多层嵌套集合处理
// 获取所有学生的选修课程(去重)
Set<String> allCourses = schools.stream()
.flatMap(school -> school.getClasses().stream())
.flatMap(clazz -> clazz.getStudents().stream())
.flatMap(student -> student.getCourses().stream())
.map(Course::getName)
.collect(Collectors.toSet());