我目前正在深入研究 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);
}
}
我的问题是:
为什么 main 方法中的行会编译?
如果我理解正确的话,引用方法的签名必须对应于功能接口(interface)的 SAM 签名。在这种情况下,消费者需要以下签名:
void accept(T t);
但是,requireNonNull
方法返回 T
而不是 void:
public static <T> T requireNonNull(T obj)
最佳答案
Java 语言规范第 8 版在 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:
- 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.
(强调我的)
因此函数类型的结果为 void 这一事实足以让它匹配。
JLS 15.12.2.5还特别提到了匹配方法时使用void。对于 lambda 表达式,有一个 void-compatible block ( 15.27.2 ) 的概念,在 15.12.2.1 中引用。 , 但没有对方法引用的等效定义。
我没能找到更具体的解释(但 JLS 是一个棘手的问题,所以也许我遗漏了一些相关部分),但我认为这与你也被允许的事实有关将非 void 方法作为自己的语句调用(没有赋值、return
等))。
JLS 15.13.3 Run-Time Evaluation of Method References还说:
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.
The effect of this determination when the compile-time declaration of the method reference is signature polymorphic is that:
- The types of the parameters for the method invocation are the types of the corresponding arguments.
- The method invocation is either void or has a return type of Object, depending on whether the invocation method which encloses the method invocation is void or has a return type.
因此生成的方法调用将是无效的以匹配功能类型。
关于java - 为什么这个 Java 8 方法引用可以编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32539100/