1. 什么是 @FunctionalInterface?
@FunctionalInterface 是一个标记注解 (Marker Annotation),用于指示一个接口是函数式接口(Functional Interface)。它是 Java 8 引入的,与 Lambda 表达式紧密相关。
2. 什么是函数式接口?
函数式接口是一个有且仅有一个抽象方法的接口(但可以有多个默认方法或静态方法)。它代表了一种单一功能的契约,是 Lambda 表达式和方法引用的目标类型。
例如,Java 标准库中的:
Runnable(抽象方法:run())Callable<V>(抽象方法:call())Comparator<T>(抽象方法:compare(T o1, T o2))
3. @FunctionalInterface 的作用
这个注解主要有两个目的:
-
编译器检查 :
当你在一个接口上使用了
@FunctionalInterface,编译器会强制检查该接口是否确实只有一个抽象方法。如果不是,编译器会报错。这有助于防止意外地添加第二个抽象方法,从而破坏其作为函数式接口的用途。 -
文档化 :
它明确地告诉代码的阅读者:"这个接口被设计为函数式接口,目的是为了与 Lambda 表达式一起使用"。
4. 基本语法
java
@FunctionalInterface
interface MyFunctionalInterface {
// 单个抽象方法
void myMethod(String msg);
// 允许有默认方法
default void defaultMethod() {
System.out.println("This is a default method.");
}
// 允许有静态方法
static void staticMethod() {
System.out.println("This is a static method.");
}
// 允许覆盖 java.lang.Object 中的方法 (这不算是抽象方法)
@Override
boolean equals(Object obj);
}
关键规则:
- 必须只有一个抽象方法。
- 可以有任意数量的
default方法。 - 可以有任意数量的
static方法。 - 覆盖
Object类的方法(如toString(),equals(),hashCode())不计入抽象方法的数量。
5. 使用示例
1. 定义函数式接口:
java
@FunctionalInterface
interface Greeting {
void sayHello(String name);
// void anotherMethod(); // 如果取消注释,编译器会报错
}
2. 使用 Lambda 表达式实现:
java
public class Main {
public static void main(String[] args) {
// 使用 Lambda 表达式实现 Greeting 接口
Greeting greet = (name) -> {
System.out.println("Hello, " + name);
};
// 调用方法
greet.sayHello("Alice"); // 输出: Hello, Alice
// 更简洁的写法
Greeting greet2 = name -> System.out.println("Hi there, " + name);
greet2.sayHello("Bob"); // 输出: Hi there, Bob
}
}
3. 作为方法参数传递(非常常见):
Lambda 表达式的强大之处在于可以像数据一样传递行为。
java
import java.util.Arrays;
import java.util.List;
public class Main {
// 一个接受函数式接口作为参数的方法
public static void processNames(List<String> names, Greeting greeting) {
for (String name : names) {
greeting.sayHello(name);
}
}
public static void main(String[] args) {
List<String> nameList = Arrays.asList("Alice", "Bob", "Charlie");
// 传递不同的 Lambda 实现来表达不同的"问候"行为
System.out.println("Formal greeting:");
processNames(nameList, name -> System.out.println("Good day, " + name));
System.out.println("\nCasual greeting:");
processNames(nameList, name -> System.out.println("Hey, " + name + "!"));
}
}
6. 总结
| 特性 | 说明 |
|---|---|
| 目的 | 定义并强制检查一个接口为函数式接口,以便与 Lambda 表达式协同工作。 |
| 强制规则 | 接口必须有且仅有一个抽象方法。 |
| 灵活性 | 允许存在多个 default 方法和 static 方法。 |
| 最佳实践 | 如果你设计的接口明确希望被用作 Lambda 表达式的目标,就应该加上 @FunctionalInterface 注解。即使不加,只要符合单一抽象方法的规则,它依然是函数式接口,但加上注解可以让意图更清晰并获得编译器的保护。 |
简单来说,@FunctionalInterface 是 Java 为支持函数式编程范式而提供的一个关键工具,它让使用 Lambda 表达式变得安全、清晰和高效。