为什么此Java 8方法参考进行编译? [英] Why does this Java 8 method reference compile?
问题描述
我目前正在更深入地研究 Java 8
功能,例如Lambda和方法引用.玩一会儿,使我进入了以下示例:
I'm currently diving deeper into Java 8
features like Lambdas and method references. Playing around a bit brought me to the following example:
public class ConsumerTest {
private static final String[] NAMES = {"Tony", "Bruce", "Steve", "Thor"};
public static void main(String[] args) {
Arrays.asList(NAMES).forEach(Objects::requireNonNull);
}
}
我的问题是:
为什么main方法内的行会编译?
Why does the line inside the main method compile ?
如果我正确理解这件事,则引用方法的签名必须与功能接口的SAM签名相对应.在这种情况下,消费者需要以下签名:
If I understood the thing correctly, the referenced method's signature has to correspond to the functional interface's SAM signature. In this case, the Consumer requires the following signature:
void accept(T t);
但是, requireNonNull
方法返回 T
而不是void:
However, the requireNonNull
method returns T
instead of void:
public static <T> T requireNonNull(T obj)
推荐答案
The Java Language Specification version 8 says in 15.13.2:
A method reference expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.
[..]
如果满足以下两个条件,则方法引用表达式与函数类型一致:
A method reference expression is congruent with a function type if both of the following are true:
- 函数类型标识与引用相对应的单个编译时声明.
- 以下条件之一为真:
- 函数类型的结果为空.
- 函数类型的结果为R,而应用捕获转换的结果为(§15.12.2.6)为R'(其中R为目标类型)可以用来推断R'),并且R和R'都不是无效的,并且R'在赋值上下文中与R兼容.
- The function type identifies a single compile-time declaration corresponding to the reference.
- One of the following is true:
- The result of the function type is void.
- The result of the function type is R, and the result of applying capture conversion (§5.1.10) to the return type of the invocation type (§15.12.2.6) of the chosen compile-time declaration is R' (where R is the target type that may be used to infer R'), and neither R nor R' is void, and R' is compatible with R in an assignment context.
(重点是我的)
因此,函数类型的结果为空的事实足以使其匹配.
So the fact the result of the function type is void, is enough for it to allow it to match.
JLS 15.12.2.5还特别提到了在匹配方法时使用void的情况.对于lambda表达式,存在 void-compatible 块的概念( 15.12.2.1 ,但是没有等效的方法引用定义.
JLS 15.12.2.5 also specifically mentions the use of void when matching methods. For lambda expression there is the notion of a void-compatible block (15.27.2) which is referenced in 15.12.2.1, but there is no equivalent definition for method references.
我无法找到更具体的解释(但是JLS很难破解,所以也许我缺少一些相关的部分),但是我认为这与允许您加入这一事实有关自己将非void方法作为语句调用(无赋值,
return
等).I haven't been able to find a more specific explanation (but the JLS is a tough nut to crack so maybe I am missing some relevant sections), but I assume this has to do with the fact that you are also allowed to invoke non-void methods as a statement on its own (without assignment,
return
etc)).出于确定编译时结果的目的,如果调用方法的结果为空,则方法调用表达式为表达式语句,如果调用方法的结果为非无效,则返回语句的表达式.
For the purpose of determining the compile-time result, the method invocation expression is an expression statement if the invocation method's result is void, and the Expression of a return statement if the invocation method's result is non-void.
当方法引用的编译时声明为签名多态时,此确定的效果是:
- 方法调用的参数类型是相应参数的类型.
- 方法调用是void还是具有Object的返回类型,这取决于包围方法调用的调用方法是void还是具有返回类型.
因此,生成的方法调用将无效以匹配功能类型.
So the generated method invocation will be void to match the functional type.
这篇关于为什么此Java 8方法参考进行编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!