函数式接口的核心是“一个抽象方法”契约,而非背诵接口名;Runnable、Predicate、Function等均由此支撑,配合Lambda、组合与泛型实现行为抽象与复用。

Java 函数式接口能力提升,关键不在背接口名,而在理解“一个抽象方法”如何驱动行为抽象、组合与复用。核心是把接口当“契约”,把 Lambda 当“实现契约的快捷写法”,再用组合和泛型把逻辑串起来。
紧扣“单抽象方法”这个硬约束
函数式接口不是语法糖,而是编译器强制的契约。只要接口里真正需要你去实现的抽象方法只有一个,它就能接 Lambda 或方法引用。@FunctionalInterface 注解只是帮你提前发现违规——比如不小心加了第二个未实现的方法,编译就报错。Runnable、Predicate、Function 都靠这条立住,不满足就无法用于 Stream、Optional 等现代 API。
- 允许存在多个 default 方法或 static 方法,它们属于工具能力,不破坏契约
- Object 类的 public 方法(如 toString、equals)不算抽象方法,不影响函数式接口判定
- Comparator 是特例:它有两个抽象方法(compare 和 equals),但 equals 被视为 Object 方法的重声明,所以仍被认定为函数式接口
吃透四大核心接口的真实分工
不必记全 43 个内置接口,先掌握 Function、Predicate、Consumer、Supplier 这四个“主干”,它们覆盖绝大多数业务场景:
- Function<T,R>:做“转换”,比如 String → Integer、User → UserDto。支持 andThen/compose 链式调用,适合构建数据处理流水线
- Predicate<T>:做“判断”,返回 boolean。常用在 filter、removeIf 中,支持 and/or/negate 组合条件
- Consumer<T>:做“消费”,只干活不返结果。适合日志、更新状态、发消息等副作用操作
- Supplier<T>:做“供给”,无参生成结果。常用于延迟计算、工厂创建、Optional.orElseGet 等场景
用组合代替嵌套,用类型推断减少冗余
Lambda 的价值不是“写得短”,而是让意图直白。例如过滤+转换,不用写两层 for 循环,直接用 Stream + Predicate + Function:
立即学习“Java免费学习笔记(深入)”;
- 避免手写 if (x != null && x.length() > 0) {...},改用 Predicate<String> notEmpty = s -> s != null && !s.trim().isEmpty()
- 避免重复 new SimpleDateFormat(...),改用 Supplier<DateFormat> formatter = () -> new SimpleDateFormat("yyyy-MM-dd")
- 链式调用时,编译器能根据上下文自动推断泛型,不必每处都写完整类型,比如 list.stream().map(String::length).filter(n -> n > 3)
从自定义接口起步,倒逼设计思维升级
别总依赖内置接口。遇到新场景(比如“校验并抛异常”“异步回调后处理”),试着自己定义 @FunctionalInterface:
- 接口命名体现意图,比如 ValidatedConsumer<T>、AsyncCallback<R>
- 方法签名聚焦单一职责,参数尽量精简,返回值明确(void / boolean / T)
- 搭配默认方法提供通用逻辑,比如重试、日志、空值保护,让使用者专注业务逻辑


















