Lambda 与 Stream API
掌握函数式接口、Lambda、方法引用、Stream 流式处理
Lambda 与 Stream API
Lambda 让代码更简洁,Stream 让集合操作更优雅。两者结合是 Java 8 最大的变革。
学完本章你将: 掌握 Lambda 语法、方法引用、Stream 声明式数据处理。
Lambda —— 把函数当参数传
Lambda 本质上是一个可传递的代码块。以前要传一段逻辑必须包在匿名类里,Lambda 让你直接写"做什么"。
java
// 之前:用匿名类传递一段逻辑
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("旧方式");
}
}).start();
// Lambda:直接写逻辑
new Thread(() -> System.out.println("Lambda 方式")).start();
// 语法:(参数) -> { 方法体 }
Comparator<String> byLength = (a, b) -> a.length() - b.length();
常用函数式接口(只有一个抽象方法的接口):
| 接口 | 作用 | 写法 |
|---|---|---|
| `Predicate | 判断真假 | `s -> s.length() > 5` |
| `Function | 转换类型 | `s -> s.length()` |
| `Consumer | 消费(无返回) | `s -> System.out.println(s)` |
| `Supplier | 提供(无参数) | `() -> Math.random()` |
方法引用 —— Lambda 的更简写法
如果 Lambda 只是调用已有方法,可以进一步简化为方法引用:
java
// Lambda
list.forEach(s -> System.out.println(s));
// 方法引用(等效)
list.forEach(System.out::println);
// 四种形式:
String::valueOf // 静态方法引用
str::length // 实例方法引用
String::length // 类名引用实例方法
ArrayList::new // 构造方法引用
Stream —— 声明式处理数据
Stream 不是数据结构,而是数据流水线。你把数据放进去,经过一系列操作(过滤→转换→排序),最后收集结果。流不会改变原始数据,每个操作返回新流。
java
List<String> names = List.of("Alice", "Bob", "Charlie", "David");
// 链式操作:过滤 → 转换 → 排序 → 收集
List<String> result = names.stream()
.filter(n -> n.length() > 3) // 中间:过滤(惰性,不触发计算)
.map(String::toUpperCase) // 中间:转换
.sorted(Comparator.reverseOrder()) // 中间:排序
.toList(); // 终止:触发计算,收集结果
System.out.println(result); // [DAVID, CHARLIE, ALICE]
中间操作 vs 终止操作: 中间操作(filter/map/sorted)只是搭流水线,不触发计算。终止操作(toList/forEach/reduce)才真正启动流水线。
java
// 常用中间操作
.filter(n -> n > 0) // 过滤
.map(n -> n * 2) // 转换
.distinct() // 去重
.sorted() // 排序
.limit(10) // 截取前10个
.skip(5) // 跳过前5个
// 常用终止操作
.toList() // 收集为 List
.forEach(System.out::println) // 遍历
.reduce(0, Integer::sum) // 聚合
.count() // 计数
.collect(Collectors.groupingBy(...)) // 分组
💡 注意: 一个 Stream 只能被消费一次。
stream.filter(...).toList()后,这个 stream 就"用完了",不能再toList()第二次。