Lambda 与函数式接口
约 858 字大约 3 分钟
布欧-Lewyon
2026-05-16
首页 › Java › 方法 › Lambda 与函数式接口
Lambda 表达式(Java 8+)提供了一种简洁的语法将行为作为参数传递,是函数式编程在 Java 中的入口。理解 Lambda 对于后续的 Stream API 和集合操作至关重要。
从匿名类到 Lambda
在 Lambda 出现之前,传递行为需要通过匿名内部类实现。以 Comparator 为例:
// 匿名内部类方式
Comparator<String> byLength = new Comparator<>() {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
};这段代码的核心逻辑只有 return Integer.compare(a.length(), b.length()),其余都是样板代码。Lambda 将其简化为:
Comparator<String> byLength = (a, b) -> Integer.compare(a.length(), b.length());Lambda 语法
(参数列表) -> { 方法体 }
(参数列表) -> 表达式 // 单条语句可省略花括号与 return// 无参数
() -> System.out.println("Hello")
// 单参数(可省略括号)
x -> x * 2
// 多参数
(a, b) -> a + b
// 多行方法体
(a, b) -> {
int sum = a + b;
System.out.println(sum);
return sum;
}Lambda 的类型由上下文推断——编译器根据赋值的变量类型或方法参数类型确定它对应哪个函数式接口。
函数式接口
函数式接口是只有一个抽象方法的接口(可以有多个 default 或 static 方法)。Java 8 在 java.util.function 包中提供了常用的函数式接口:
| 接口 | 方法签名 | 用途 |
|---|---|---|
Predicate<T> | boolean test(T t) | 条件判断 |
Function<T,R> | R apply(T t) | 类型转换 |
Consumer<T> | void accept(T t) | 消费数据 |
Supplier<T> | T get() | 提供数据 |
UnaryOperator<T> | T apply(T t) | 同类型转换 |
BinaryOperator<T> | T apply(T t1, T t2) | 同类型合并 |
// Predicate:判断字符串是否为空
Predicate<String> nonEmpty = s -> !s.isEmpty();
// Function:字符串转长度
Function<String, Integer> strLen = s -> s.length();
// Consumer:打印元素
Consumer<String> printer = s -> System.out.println(s);
// Supplier:生成默认值
Supplier<String> defaultName = () -> "Guest";方法引用
当 Lambda 体仅仅是调用一个已有方法时,可用方法引用进一步简化:
| 形式 | 示例 | 等价 Lambda |
|---|---|---|
类::静态方法 | Math::max | (a, b) -> Math.max(a, b) |
对象::实例方法 | System.out::println | x -> System.out.println(x) |
类::实例方法 | String::length | s -> s.length() |
类::new | ArrayList::new | () -> new ArrayList() |
// 实例方法引用
list.forEach(System.out::println);
// 静态方法引用
list.stream().map(String::valueOf).collect(Collectors.toList());
// 构造器引用
Supplier<List<String>> listSupplier = ArrayList::new;变量捕获
Lambda 可以访问外部的 final 或事实上不可变(effectively final)的局部变量:
String prefix = "User: "; // 后面未修改,effectively final
list.forEach(name -> System.out.println(prefix + name));如果局部变量在 Lambda 中被修改,编译报错。实例字段和静态字段不受此限制(但注意线程安全)。
小结
- Lambda 语法:
(参数) -> 表达式或(参数) -> { 语句 },类型由上下文推断。 - 函数式接口只有一个抽象方法,
@FunctionalInterface注解可让编译器检查。 java.util.function四大核心接口:Predicate(判断)、Function(转换)、Consumer(消费)、Supplier(供应)。- 方法引用(
类::方法)进一步简化 Lambda,适合仅调用已有方法时使用。 - Lambda 只能捕获 effectively final 的局部变量。
- 易错:Lambda 中的
this指向外部类实例而非 Lambda 自身(匿名类的this指向匿名类实例)——与匿名内部类行为不同,容易混淆。 - 思考任务:用 Lambda 实现
List<String>的排序(按字符串长度),再用方法引用写一遍对比简洁度。
上一节:方法
