函数式接口本质是仅含一个用户声明抽象方法的接口,支持default/static方法;@FunctionalInterface仅为编译校验与意图声明,不改变行为。

Java 中的函数式接口,本质就是一个只含一个抽象方法的接口,它是 Lambda 表达式和方法引用的底层支撑类型。
函数式接口的核心特征
它不是靠注解定义的,而是由结构决定的:接口中必须有且仅有一个**用户声明的抽象方法**(不包括从 Object 继承的 toString()、equals()、hashCode() 等)。其他成员可以存在,但不破坏“单抽象方法”规则:
- 允许任意数量的 default 方法(如
Stream接口里的forEachOrdered()) - 允许任意数量的 static 方法(如
Comparator中的naturalOrder()) - 不能有第二个用户定义的抽象方法,否则编译报错(即使没加
@FunctionalInterface)
@FunctionalInterface 注解的作用
这个注解本身不改变接口行为,而是起编译期校验 + 意图声明作用:
- 加上后,编译器会严格检查:若抽象方法数量 ≠ 1,立即报错
- 它是一种“设计契约”,告诉其他开发者:“这个接口就是为 Lambda 准备的”
- 不加也能用——只要结构满足,JDK 内置的
Runnable、Callable、Comparator在 Java 8 之前就已是函数式接口,后来才补上该注解
如何自定义并使用函数式接口
定义时推荐显式添加注解,避免误加方法破坏语义。例如:
立即学习“Java免费学习笔记(深入)”;
@FunctionalInterface
public interface MathOperation {
int apply(int a, int b); // 唯一抽象方法
default int square(int x) { return x * x; }
static boolean isPositive(int n) { return n > 0; }
}使用方式直接对应 Lambda 或方法引用:
- Lambda:
MathOperation add = (x, y) -> x + y; - 方法引用:
MathOperation mul = Integer::sum;(前提是方法签名匹配) - 传参:可作为参数用于高阶函数,比如
process(5, 3, (a,b) -> a - b)
常见误区提醒
容易混淆的点要特别注意:
-
@FunctionalInterface不是“让接口变成函数式”的开关,只是校验工具 - 接口继承另一个函数式接口,若未重写抽象方法,则子接口仍算函数式接口(抽象方法数仍是 1)
- 如果接口继承了
Runnable又自己声明了一个抽象方法,那就变成两个抽象方法 → 不再是函数式接口 -
void run()和Object.toString()共存不冲突,后者不算抽象方法增量


















