函数式接口本质是仅含一个抽象方法的契约,为Lambda提供唯一实现目标;四大核心接口按输入输出逻辑分工:Supplier产出、Consumer消费、Function转换、Predicate判断;组合(andThen/compose/and/or)提升表达力,但需避免副作用与过度使用。

函数式接口不是语法糖,而是 Java 函数式编程的“契约”——它用一个抽象方法定义行为边界,让 Lambda 和方法引用有据可依。理清它,关键不在背接口名,而在理解“为什么只允许一个抽象方法”以及“怎么选、怎么用、怎么组合”。
盯住核心:一个抽象方法是硬约束
函数式接口的本质,是为 Lambda 表达式提供唯一可实现的目标。编译器靠这个规则做类型推断和校验:
- @FunctionalInterface 是提示性注解,不是必需项,但强烈建议加上——它会在你意外添加第二个抽象方法时立刻报错
- 可以有任意多个 default 方法和 static 方法,它们不破坏“单一行为”的契约,只是补充能力(比如 Predicate 的 and/or/negate 就是 default 方法)
- Runnable、Comparator、Comparable 这些老接口虽未加注解,但因历史原因只含一个抽象方法,也天然支持 Lambda
四大核心接口,按输入输出对号入座
别死记包名和方法名,记住“谁要什么、给什么”这个逻辑链:
-
Supplier
:无输入,只产出 —— 适合创建对象、生成随机数、延迟计算(如日志拼接优化场景) -
Consumer
:有输入,不返回 —— 适合打印、存库、发消息等“消费动作” -
Function
:有输入,有返回 —— 适合转换、映射、加工(如 String::length、user::getName) -
Predicate
:有输入,返回 boolean —— 专用于条件判断(filter、if/else 抽象)
进阶用法:andThen、compose、and、or 不是炫技,是组合逻辑
单个函数接口解决不了复杂流程,组合才是生产力:
- Function.andThen(f):先执行当前函数,再把结果传给 f —— 适合“加工后处理”,比如 parse → validate → save
- Function.compose(f):先执行 f,再把结果传给当前函数 —— 适合“预处理”,比如 trim → toUpperCase → hash
- Predicate.and(p) / or(p) / negate():把多个判断条件像布尔表达式一样拼装,避免嵌套 if
- BiFunction、UnaryOperator 等扩展接口,本质是上述四类的参数或类型变体,用到再查,不必提前 memorize
实战避坑:别让函数式变成“伪函数式”
真正发挥函数式优势,得守住几个底线:
- 避免在 Consumer 或 Supplier 里修改外部状态(如 ++i、list.add()),这会破坏不可变性和线程安全
- Lambda 体中别写太长逻辑,超过 3 行就该提取成具名方法,再用方法引用 :: 调用
- 不要为了用而用:简单循环、明确步骤的业务逻辑,for 循环更直白;Stream + 函数式更适合数据转换、过滤、聚合这类声明式操作
- 注意 null 安全:Predicate.test(null)、Function.apply(null) 可能抛 NPE,必要时用 Objects::nonNull 或 Optional 包裹
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











