java - 为什么这个 Java 8 方法引用可以编译?

标签 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);
   }
}

我的问题是:

为什么 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/

相关文章:

java - MATLAB:从 MATLAB 获取单元格数组到 Java

java - AspectJ 方面排序

java - 我正在寻找java web框架

java - 九人莫里斯游戏的位板表示

Java 8 Lambda - 两个列表的交集

java - 从函数指针列表中获取函数的索引

java - 我如何打印这个流?

java - 何时倾向于采用 Consumer<T> 而不是仅仅返回 T?

java - Bicycle[]::new 的等价物是什么

java - 为什么我不能使用 LinkedList::new?