@FunctionalInterface
函数式接口详解
@FunctionalInterface
是 Java 8 引入的注解,用于标记只有一个抽象方法的接口。这种接口可以直接用 Lambda 表达式或方法引用来实现,是函数式编程的核心特性。
核心特性
- 单抽象方法
接口中只能有一个抽象方法(但可以有默认方法或静态方法)。 - Lambda 支持
可以用 Lambda 表达式快速实现接口。 - 编译检查
添加@FunctionalInterface
后,编译器会强制检查是否满足函数式接口的条件。
经典案例
1. Java 内置的函数式接口
java
// Runnable(无参数、无返回值)
Runnable task = () -> System.out.println("Hello, Lambda!");
task.run();
// Predicate<T>(输入T,返回boolean)
Predicate<String> isEmpty = s -> s.isEmpty();
System.out.println(isEmpty.test("")); // true
// Function<T, R>(输入T,返回R)
Function<String, Integer> strToLength = String::length;
System.out.println(strToLength.apply("Java")); // 4
// Runnable(无参数、无返回值)
Runnable task = () -> System.out.println("Hello, Lambda!");
task.run();
// Predicate<T>(输入T,返回boolean)
Predicate<String> isEmpty = s -> s.isEmpty();
System.out.println(isEmpty.test("")); // true
// Function<T, R>(输入T,返回R)
Function<String, Integer> strToLength = String::length;
System.out.println(strToLength.apply("Java")); // 4
2. 自定义函数式接口
java
@FunctionalInterface
interface Calculator {
int calculate(int a, int b); // 唯一抽象方法
// 默认方法(不影响函数式接口性质)
default void log() {
System.out.println("Calculating...");
}
}
public class Main {
public static void main(String[] args) {
// 用Lambda实现
Calculator add = (a, b) -> a + b;
System.out.println(add.calculate(3, 5)); // 8
// 用方法引用实现(假设有静态方法)
Calculator multiply = Main::staticMultiply;
System.out.println(multiply.calculate(3, 5)); // 15
}
static int staticMultiply(int a, int b) {
return a * b;
}
}
@FunctionalInterface
interface Calculator {
int calculate(int a, int b); // 唯一抽象方法
// 默认方法(不影响函数式接口性质)
default void log() {
System.out.println("Calculating...");
}
}
public class Main {
public static void main(String[] args) {
// 用Lambda实现
Calculator add = (a, b) -> a + b;
System.out.println(add.calculate(3, 5)); // 8
// 用方法引用实现(假设有静态方法)
Calculator multiply = Main::staticMultiply;
System.out.println(multiply.calculate(3, 5)); // 15
}
static int staticMultiply(int a, int b) {
return a * b;
}
}
实际应用场景
1. 简化回调逻辑
java
@FunctionalInterface
interface Callback {
void onComplete(String result);
}
void fetchData(Callback callback) {
// 模拟异步操作
new Thread(() -> {
String data = "Data fetched";
callback.onComplete(data);
}).start();
}
// 调用
fetchData(result -> System.out.println("Result: " + result));
@FunctionalInterface
interface Callback {
void onComplete(String result);
}
void fetchData(Callback callback) {
// 模拟异步操作
new Thread(() -> {
String data = "Data fetched";
callback.onComplete(data);
}).start();
}
// 调用
fetchData(result -> System.out.println("Result: " + result));
2. 策略模式
java
@FunctionalInterface
interface PaymentStrategy {
void pay(double amount);
}
class PaymentService {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
strategy.pay(amount);
}
}
// 使用
PaymentService service = new PaymentService();
service.setStrategy(amount -> System.out.println("Paid via Credit Card: $" + amount));
service.executePayment(100.0);
@FunctionalInterface
interface PaymentStrategy {
void pay(double amount);
}
class PaymentService {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
strategy.pay(amount);
}
}
// 使用
PaymentService service = new PaymentService();
service.setStrategy(amount -> System.out.println("Paid via Credit Card: $" + amount));
service.executePayment(100.0);
常见问题
为什么要有
@FunctionalInterface
注解?- 明确告知开发者该接口的用途(如
Runnable
一看就知道是任务执行)。 - 编译器会检查是否真的只有一个抽象方法。
- 明确告知开发者该接口的用途(如
没有这个注解的接口能用 Lambda 吗?
- 可以!只要实际满足函数式接口的条件(单一抽象方法),但加上注解更规范。
抽象方法能是
Object
类中的方法吗?- 不算!例如
equals()
是Object
的方法,不会影响函数式接口的性质。
java@FunctionalInterface interface Example { void doSomething(); boolean equals(Object obj); // 不计数 }
@FunctionalInterface interface Example { void doSomething(); boolean equals(Object obj); // 不计数 }
- 不算!例如
总结
- 本质:函数式接口是 Lambda 的“目标类型”。
- 用途:简化代码(替代匿名类)、实现策略模式、事件回调等。
- 关键点:记住
单一抽象方法
规则,其他都是锦上添花。