Z
ZHANK
编程在线教程Java 教程Lambda 与 Stream API
实战进阶

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() 第二次。