1. 什么是 Stream 流?
Stream
是 Java 8 引入的全新集合处理方式,旨在用 函数式编程 的思想处理数据,极大减少了代码量和复杂度。
它不是集合,也不存储数据,而是基于数据源(如集合、数组、I/O)进行 声明式、链式操作
关键理念:数据源 → 一系列中间操作(加工、过滤) → 终止操作(收集、输出、聚合)
2. 为什么叫“链式编程”?
传统写法通常需要 循环+条件+中间变量,Stream 则通过方法链连续调用,每一步返回新的 Stream 对象,最终以一个终止方法结束。例子对比:
// 传统写法
List<String> list = Arrays.asList("apple", "banana", "pear", "orange");
List<String> result = new ArrayList<>();
for (String s : list) {
if (s.length() > 5) {
result.add(s.toUpperCase());
}
}
System.out.println(result);
// Stream 链式写法
List<String> result2 = list.stream()
.filter(s -> s.length() > 5) // 过滤
.map(String::toUpperCase) // 转大写
.toList(); // 收集结果
System.out.println(result2);
3. Stream 链式编程核心结构
一个完整的链式编程通常包含 三步:
-
获取流(创建数据流)
-
中间操作(加工、转换,可多个)
-
终止操作(触发执行)
dataSource.stream() // 1. 获取流
.filter(...) // 2. 中间操作
.map(...) // 2. 中间操作
.sorted(...) // 2. 中间操作
.collect(...); // 3. 终止操作
4. 常见中间操作(Intermediate Operations)
中间操作是惰性求值,不会立即执行,直到遇到终止操作。
方法 | 作用 | 示例 |
---|---|---|
filter(Predicate) | 过滤 | .filter(x -> x > 5) |
map(Function) | 数据转换 | .map(String::length) |
flatMap(Function) | 扁平化流 | .flatMap(List::stream) |
distinct() | 去重 | .distinct() |
sorted() / sorted(Comparator) | 排序 | .sorted(Comparator.reverseOrder()) |
limit(n) | 截取前 n 个 | .limit(3) |
skip(n) | 跳过前 n 个 | .skip(2) |
peek(Consumer) | 调试/查看中间值 | .peek(System.out::println) |
5. 常见终止操作(Terminal Operations)
终止操作会触发流的执行,并产生结果或副作用。
方法 | 作用 | 示例 |
---|---|---|
collect(Collector) | 收集结果 | .collect(Collectors.toList()) |
toList() | 收集到 List(Java 16+) | .toList() |
forEach(Consumer) | 遍历 | .forEach(System.out::println) |
count() | 计数 | .count() |
reduce() | 聚合计算 | .reduce(0, Integer::sum) |
min() / max() | 最小/最大值 | .max(Integer::compareTo) |
anyMatch() / allMatch() / noneMatch() | 条件匹配 | .anyMatch(x -> x > 10) |
findFirst() / findAny() | 获取元素 | .findFirst().orElse(null) |
6. 链式编程案例
案例 1:员工工资处理
import java.util.*;
import java.util.stream.*;
class Employee {
String name;
double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() { return name; }
public double getSalary() { return salary; }
}
public class StreamDemo {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Tom", 5000),
new Employee("Jerry", 7000),
new Employee("Lily", 9000),
new Employee("Lucy", 12000)
);
List<String> highSalaryNames = employees.stream()
.filter(e -> e.getSalary() > 8000) // 工资 > 8000
.sorted(Comparator.comparing(Employee::getSalary).reversed()) // 按工资降序
.map(Employee::getName) // 提取姓名
.toList(); // 收集结果
System.out.println(highSalaryNames); // [Lucy, Lily]
}
}
案例 2:单词去重统计
List<String> words = Arrays.asList("apple", "banana", "apple", "orange", "banana");
long count = words.stream()
.distinct() // 去重
.count(); // 统计数量
System.out.println(count); // 3
7. 链式编程的优点
-
简洁:减少样板代码
-
可读性高:逻辑步骤清晰
-
可组合性:中间操作可随意组合
-
并行化支持:可直接
.parallelStream()
提升性能
8. 注意事项
-
Stream 只能使用一次,用完就要重新获取。
-
中间操作是惰性执行的,没有终止操作不会触发。
-
并行流虽然能提升性能,但在小数据量或线程不安全场景可能反而更慢。
-
.peek()
适合调试,生产代码不要依赖它改变数据。
✅ 总结:
Java Stream 的链式编程,本质上是函数式编程 + 方法链调用,让你能用声明式的方式处理集合数据,代码更简洁、逻辑更清晰、可读性更高。