为何Java方法引用可编译但等价Lambda表达式编译失败
Java方法引用与Lambda参数适配规则差异解答
示例代码
import java.util.function.Consumer; public class MethRefVsLambdaExpr { public static void main(String[] args) { //1. 以下代码可正常编译 Consumer<String> cs1 = MethRefVsLambdaExpr::objParamMeth; //2. 以下代码抛出编译错误: //Lambda 表达式的参数 o 预期为 String 类型 Consumer<String> cs2 = (Object o) ->{}; } static void objParamMeth(Object o) {} }
问题1:为何方法引用可编译,显式指定参数的Lambda编译失败
- 首先明确
Consumer<String>的函数式方法签名为void accept(String t),要求传入一个String类型的参数,无返回值。 - 方法引用的适配规则:方法引用只要求参数可以安全转换即可。这里
objParamMeth接收Object类型参数,String是Object的子类,传入的String参数可以自动向上转型为Object,没有任何类型安全问题,所以编译器允许该赋值。 - Lambda表达式的适配规则:如果你显式声明了Lambda的参数类型,就必须和目标函数式接口的参数类型完全一致,不能做向上/向下转型兼容。你这里显式把参数声明为Object,和要求的String不匹配,所以直接报编译错误。如果省略参数类型让编译器自动推导,写成
Consumer<String> cs2 = o -> {},编译器会自动把o的类型推断为String,就可以正常编译。
问题2:是否有官方规则说明
Oracle官方的《Java语言规范》(JLS)中有明确规则定义:
JLS 15.13.2 方法引用的类型适配:当方法引用赋值给函数式接口类型时,只要函数式接口方法的每个参数都可以安全转换为方法引用对应方法的参数类型,该赋值就是合法的。
JLS 15.27.3 Lambda表达式的类型适配:如果Lambda表达式显式声明了参数类型列表,那么每个参数的类型必须与对应函数式接口方法的参数类型完全相等。
内容的提问来源于stack exchange,提问作者Vik
相关产品推荐
相关产品推荐

