自定义函数式接口旨在明确抽取业务中“变的部分”,使主流程专注“做什么”而非“怎么做”,需满足接口声明、唯一抽象方法、@functionalinterface注解等函数式语义要求。

自定义函数式接口不是为了多写一个接口,而是把业务中“变的部分”明确抽出来,让主流程只关注“做什么”,不关心“怎么做”。关键在清晰表达意图、严格满足函数式语义、兼顾类型安全和复用性。
必须满足函数式语义
一个合法的自定义函数式接口要同时满足:
- 用 interface 声明,不能是类或抽象类
- 有且仅有一个未被重写的公共抽象方法(比如 boolean check(LoanApplication app))
- 强烈建议加上 @FunctionalInterface 注解——它不改变运行行为,但能防止后续误加抽象方法导致编译失败
- 可以包含 default 方法、static 方法、Object 的 public 方法(如 equals、hashCode),这些不破坏函数式契约
方法命名要体现业务动作
避免泛化命名(如 doIt、handle、process),直接用动词+上下文表达真实意图:
- ✅ 推荐:boolean isEligibleForPromotion(Employee emp) —— 明确是晋升资格判断
- ✅ 推荐:Order adjustPrice(Order order, DiscountPolicy policy) —— 表达价格调整行为与依赖
- ❌ 避免:Object apply(Object o) —— 类型模糊,丧失编译期检查能力
- 若参数较多,优先封装为领域对象(如 ApprovalContext),而不是堆砌 4~5 个原始类型参数
用泛型提升类型安全和复用性
当同一逻辑需适配不同领域对象时,泛型比 Object 更可靠:
- 定义:@FunctionalInterface interface Validator
{ boolean validate(T target); } - 使用:Validator
orderValidator = o -> o.getStatus() == OrderStatus.PAID; - 效果:编译器会阻止你把 User 实例传给 orderValidator.validate(),错误提前暴露
- 不要靠运行时 instanceof 或强制转型来绕过类型约束
结合业务场景选择实现方式
接口定义好后,具体实现按复杂度选:
- 简单规则(如字段非空校验、金额正负判断)→ 直接用 Lambda:Predicate
isActive = u -> u.getStatus() == Status.ACTIVE; - 中等逻辑(含外部服务调用、缓存、日志)→ 封装为独立类,通过构造器注入依赖,方便单元测试
- 需要组合或链式处理(如先校验再转换再通知)→ 利用 Function.andThen()、Predicate.and() 等默认方法做编排
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











