Java Lambda 表达式
函数式接口的概念
函数式接口本质上仍是一个 接口,但有一个严格约束:必须且只能有一个抽象方法(Abstract Method)
@FunctionalInterface
public interface MyFunction {
void apply(); // 唯一的抽象方法
}
注:可以有多个默认方法(default)、静态方法(static)、可以重写 Object 的方法,但只能有一个抽象方法;
注:@FunctionalInterface 注解不是必须的,但强烈建议加上,因为它提供了:
- 编译期校验,防止误加多个抽象方法
- 提升代码可读性,直接告诉别人,这是给 Lambda 用的函数式接口
函数式接口的写法
传统写法
// 定义接口和抽象方法
interface Strategy {
int apply(int x);
}
// 实例化对象,并实现抽象方法
Strategy s = new Strategy() {
@Override
public int apply(int x) {
return x * 2;
}
};
Lambda 写法
// 创建一个 Strategy 接口的实现,并声明 x 为其中唯一的抽象方法的入参,
// x -> x * 2 是 对 apply(int x) 方法的实现,其中 x 是方法参数, x * 2 是方法体的返回值
Strategy s = x -> x * 2;
调用方式
int result = s.apply(10);
Lambda 其它写法
// 实现是多行逻辑时
Strategy s = x -> {
int result = x * 2;
result += 10;
return result;
};
// 多个入参时
Strategy s = (a, b) -> {
int sum = a + b;
return sum * 2;
};
// 入参带类型时
Strategy s = (int x) -> {
if (x < 0) {
return 0;
}
int result = x * 2;
return result;
};
实际应用场景
如下,开发者定义实现,框架负责执行:
.authorizeHttpRequests(auth -> {
auth.requestMatchers("/admin/**").hasRole("ADMIN");
auth.requestMatchers("/user/**").hasRole("USER");
auth.anyRequest().authenticated();
});
函数式接口的意义于:你只负责提供“行为”实现,让调用方(框架 / API)掌控执行时机。也就是把“行为”抽象成参数,使调用方(框架/API)可以在合适的时机、以合适的方式去执行,从而实现解耦、组合与扩展。
函数式接口在早已存在,但由于语法成本高、使用不便,主要用于设计模式;但 Lambda 的出现简化了其语法、降低使用复杂度,使函数式编程成为了主流实践。