pkl*_*nst 14 java java-8 method-reference
我正在深入探讨 Java 8 Lambda和方法参考等功能.玩了一下让我看到以下示例:
public class ConsumerTest {
private static final String[] NAMES = {"Tony", "Bruce", "Steve", "Thor"};
public static void main(String[] args) {
Arrays.asList(NAMES).forEach(Objects::requireNonNull);
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
为什么main方法中的行会编译?
如果我理解正确的话,引用的方法的签名必须对应于功能接口的SAM签名.在这种情况下,消费者需要以下签名:
void accept(T t);
Run Code Online (Sandbox Code Playgroud)
但是,该requireNonNull方法返回T而不是void:
public static <T> T requireNonNull(T obj)
Run Code Online (Sandbox Code Playgroud)
Mar*_*eel 13
Java语言规范版本8在15.13.2中说:
如果T是函数接口类型,则方法引用表达式在赋值上下文,调用上下文或具有目标类型T的转换上下文中是兼容的(§9.8)),并且表达式与从T派生的地面目标类型的函数类型一致,则.
[..]
如果满足以下两个条件,则方法引用表达式与函数类型一致:
- 函数类型标识与引用相对应的单个编译时声明.
- 以下之一是真的:
- 函数类型的结果为void.
- 函数类型的结果是R,并且将捕获转换(第5.1.10节)应用于所选编译时声明的调用类型(第15.12.2.6节)的返回类型的结果是R'(其中R是可以用于推断R')的目标类型,并且R和R'都不是空的,并且R'在赋值上下文中与R兼容.
(强调我的)
所以函数类型的结果是无效的,这足以让它匹配.
JLS 15.12.2.5还特别提到匹配方法时使用void.对于lambda表达式,存在一个与void兼容的块(15.27.2)的概念,该块在15.12.2.1中引用,但是没有方法引用的等效定义.
我还没有找到更具体的解释(但JLS是一个难以破解的难题,所以也许我错过了一些相关部分),但我认为这与你也被允许调用非事实有关. -void方法作为一个单独的语句(没有赋值return等)).
为了确定编译时结果,如果调用方法的结果为void,则方法调用表达式是表达式语句;如果调用方法的结果为非void,则返回语句的表达式.
当方法引用的编译时声明是签名多态时,此确定的效果是:
- 方法调用的参数类型是相应参数的类型.
- 方法调用是void或具有Object的返回类型,具体取决于包含方法调用的调用方法是void还是具有返回类型.
因此,生成的方法调用将为void以匹配函数类型.