@FunctionalInterface自定义函数式接口需满足单抽象方法(SAM)规则:仅保留一个未实现的抽象方法,可添加任意default、static及Object方法;加注解能明确意图并编译期校验。

用 @FunctionalInterface 自定义业务接口,核心就两点:明确抽象行为 + 编译期防错。它不是语法必需,但加了能提前暴露设计问题,让接口意图更清晰。
怎么写一个合法的自定义函数式接口
接口必须满足“单抽象方法”(SAM)规则,其余都是辅助:
- 只保留一个未实现的抽象方法,比如
boolean check(User user)或Order process(OrderInput input) - 可以加任意个
default方法(带实现),比如日志、校验封装、空值处理逻辑 - 可以加任意个
static方法(工具类风格),比如工厂构造、常量判断 - 允许声明
equals、hashCode、toString这些Object方法,它们不计入抽象方法数
结合业务场景举个真实例子
假设做电商风控,需要统一接入多种审核策略:
@FunctionalInterface
public interface RiskValidator<T> {
// 唯一抽象方法:执行具体校验逻辑
ValidationResult validate(T input);
// default 方法封装通用流程(不破坏 SAM)
default ValidationResult safeValidate(T input) {
if (input == null) {
return ValidationResult.fail("输入为空");
}
return validate(input);
}
// static 工具方法
static <T> RiskValidator<T> alwaysPass() {
return input -> ValidationResult.success();
}
}
这样定义后,就能直接用 Lambda 表达式传入业务逻辑:
立即学习“Java免费学习笔记(深入)”;
RiskValidator<Order> highAmountValidator = order -> {
return order.getAmount() > 10000
? ValidationResult.fail("订单金额超限")
: ValidationResult.success();
};
容易踩坑的几个关键点
加了注解反而编译失败?常见原因有:
- 接口继承了另一个接口,而父接口里已有抽象方法,子接口又没重写成 default,导致合并后抽象方法 > 1
- 不小心写了两个没有实现的方法,比如
validate()和supportType()都没加default - 把泛型方法误当成多个抽象方法(不会,泛型擦除后仍是同一个签名)
- 用了
private方法(Java 9+ 才支持,且 private 方法不算抽象方法)
要不要加 @FunctionalInterface 注解
推荐加,理由很实在:
- 别人一眼看懂这个接口是为 Lambda 准备的,不是普通契约接口
- IDE 和编译器立刻报错,避免后续重构时无意中加了第二个抽象方法
- 团队协作时降低理解成本,尤其对新成员或跨模块调用
不加也能用,只要它客观上只有一个抽象方法,但等于主动放弃一层保护。


















