函数式接口不是语法糖,而是将行为抽象为可传递、可组合、可复用的一等公民;其核心是仅含一个抽象方法的接口,支持lambda实现,用于精准匹配场景——如function做转换、predicate做判断、consumer做消费、supplier做生成、bifunction处理双输入,并强调组合优于重复、优先使用标准库、自定义需加@functionalinterface注解且遵守变量捕获限制。

函数式接口不是语法糖,而是把“行为”变成可传递、可组合、可复用的一等公民。用好它,关键不在背接口名,而在理解什么时候该用、怎么串、如何避免常见陷阱。
明确场景再选接口,别硬套
先看你要解决的问题类型,再匹配最贴切的内置接口:
- 要对数据做转换(比如字符串转大写、数字加2)→ 用 Function
- 要判断真假(比如过滤偶数、检查非空)→ 用 Predicate
- 要消费数据但不返回结果(比如打印日志、存入数据库)→ 用 Consumer
- 要无参生成一个值(比如 new Random()::nextInt、LocalDateTime::now)→ 用 Supplier
- 要处理两个输入(比如合并姓名和年龄、计算两数之和)→ 用 BiFunction
或 BiPredicate
强行用 Function 做日志打印,或用 Supplier 做过滤判断,代码会别扭且易出错。
组合比重复写更高效
Function 和 Predicate 都支持链式组合,这是函数式编程的核心优势之一:
- andThen():先执行当前函数,再执行传入的函数(从左到右)
- compose():先执行传入的函数,再执行当前函数(从右到左)
-
Predicate.and() / or() / negate():拼接多个条件,比如
isEven.and(isPositive).negate()
例如:把字符串先去空格、再转大写、最后加前缀,可写成:
Function
Function
Function
System.out.println(pipeline.apply(" hello ")); // 【HELLO】
自定义接口要克制,优先用标准库
除非业务逻辑高度专属(比如风控系统里的 RuleEvaluator<order></order>),否则别轻易自定义函数式接口。Java 的 java.util.function 已覆盖绝大多数通用模式:
- 单参数单返回 → Function
- 单参数无返回 → Consumer
- 无参数有返回 → Supplier
- 单参数返回 boolean → Predicate
- 双参数单返回 → BiFunction
- 还有 IntFunction、LongConsumer 等原始类型特化版,避免装箱开销
自定义时务必加 @FunctionalInterface 注解,编译器会帮你守住“只有一个抽象方法”的底线。
注意 Lambda 捕获变量的限制
Lambda 内部能访问的外部变量,必须是 final 或“事实上的 final”(声明后没被重新赋值):
- 允许:
String prefix = "v1_"; list.forEach(s -> System.out.println(prefix + s)); - 禁止:
String prefix = "v1_"; list.forEach(s -> { prefix += "_tmp"; System.out.println(prefix); });(编译报错)
如需累积状态,改用外部容器(如 AtomicInteger、StringBuilder)或 Collector —— 别在 Lambda 里改局部变量。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











