函数式接口和lambda表达式通过“精准匹配”协同工作:接口须有且仅有一个抽象方法(@functionalinterface强制校验),lambda则严格遵循其签名;应优先复用java.util.function内置接口,自定义时需语义清晰、类型明确。

函数式接口和 Lambda 表达式是 Java 8 引入函数式编程能力的两个核心组件,它们配合的关键在于“精准匹配”——接口定义决定 Lambda 能怎么写,Lambda 实现则必须严格遵循接口抽象方法的签名。
函数式接口必须满足“唯一抽象方法”原则
一个接口要成为函数式接口,只能有一个抽象方法(public abstract),其他成员如 default、static 方法或继承自 Object 的方法(如 equals、toString)不计入数量。这是 Lambda 能被识别并绑定的底层依据。
- 务必添加
@FunctionalInterface注解:它不是装饰,而是编译器强制校验机制;加了之后,多写一个抽象方法会直接编译失败 - 避免从多个父接口继承抽象方法:比如同时 extends
Runnable和Comparable,会导致两个抽象方法,不再合法 - 常见合法示例:
Runnable(run())、Predicate<t></t>(test(T))、Function<t></t>(apply(T))
Lambda 写法必须与抽象方法签名完全对应
Lambda 不是万能模板,它本质上是对接口中那个唯一抽象方法的实现体。参数个数、类型、返回值类型,都由接口方法声明决定。
- 无参无返回 →
() -> System.out.println("ok") - 单参且类型可推断 →
s -> s.length() > 5(不用写(String s)) - 双参需括号 →
(a, b) -> a + b - 多语句或需显式 return →
(x, y) -> { int sum = x + y; return sum > 100; }
善用内置函数式接口,少重复造轮子
Java 的 java.util.function 包已覆盖绝大多数场景,优先复用比自定义更安全、更易理解。
-
Predicate<t></t>:做判断,如list.removeIf(s -> s.isEmpty()) -
Function<t></t>:做转换,如map.computeIfAbsent(key, k -> new ArrayList()) -
Consumer<t></t>:做消费,如list.forEach(System.out::println) -
Supplier<t></t>:做延迟生产,如Optional.ofNullable(val).orElseGet(() -> computeDefault())
自定义时聚焦语义清晰与类型明确
真需要自定义函数式接口时,重点不在“能不能用 Lambda”,而在“好不好读、好不好维护”。
- 方法名用通用动词:如
test、apply、convert、filter,避免生造术语 - 参数类型尽量基础或泛型约束明确:用
int process(int x)比Result handle(Input input)更利于类型推断 - 返回值类型别用模糊泛型或
Object:否则 Lambda 中容易出现编译错误或运行时异常
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











