gpt4 book ai didi

java - Lambda表达式和方法重载的疑惑

转载 作者:IT老高 更新时间:2023-10-28 20:35:29 26 4
gpt4 key购买 nike

好的,所以方法重载是坏事™。现在这已经解决了,让我们假设我实际上想要重载这样的方法:

static void run(Consumer<Integer> consumer) {
System.out.println("consumer");
}

static void run(Function<Integer, Integer> function) {
System.out.println("function");
}

在 Java 7 中,我可以使用明确的匿名类作为参数轻松调用它们:

run(new Consumer<Integer>() {
public void accept(Integer integer) {}
});

run(new Function<Integer, Integer>() {
public Integer apply(Integer o) { return 1; }
});

现在在 Java 8 中,我当然想用 lambda 表达式调用这些方法,而且我可以!

// Consumer
run((Integer i) -> {});

// Function
run((Integer i) -> 1);

既然编译器应该能够推断出Integer,那我为什么不把Integer放在一边呢?

// Consumer
run(i -> {});

// Function
run(i -> 1);

但这不能编译。编译器(javac,jdk1.8.0_05)不喜欢这样:

Test.java:63: error: reference to run is ambiguous
run(i -> {});
^
both method run(Consumer<Integer>) in Test and
method run(Function<Integer,Integer>) in Test match

对我来说,凭直觉,这没有意义。产生返回值(“值兼容”)的 lambda 表达式和产生 void(“void-compatible”)的 lambda 表达式之间绝对没有歧义,如 JLS §15.27 中所述。

当然,JLS 是深刻而复杂的,我们继承了 20 年的向后兼容历史,并且有一些新的东西,例如:

Certain argument expressions that contain implicitly typed lambda expressions (§15.27.1) or inexact method references (§15.13.1) are ignored by the applicability tests, because their meaning cannot be determined until a target type is selected.

from JLS §15.12.2

上述限制可能与 JEP 101 没有一路实现有关,如 herehere 所示。

问题:

谁能准确告诉我 JLS 的哪些部分指定了这种编译时歧义(或者是编译器错误)?

奖励:为什么事情会这样决定?

更新:

使用 jdk1.8.0_40,上面的编译和工作正常

最佳答案

我想你找到了this bug in the compiler: JDK-8029718 (or this similar one in Eclipse: 434642)。

比较 JLS §15.12.2.1. Identify Potentially Applicable Methods :

  • A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true:

    • The arity of the target type's function type is the same as the arity of the lambda expression.

    • If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).

    • If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).

请注意“void 兼容 block ”和“值兼容 block ”之间的明显区别。虽然在某些情况下一个 block 可能两者兼有,但 §15.27.2. Lambda Body 部分明确指出像 () -> {} 这样的表达式是“void 兼容 block ”,因为它正常完成而不返回值。并且应该很明显 i -> {} 也是一个“void 兼容 block ”。

根据上面引用的部分,将 lambda 与不兼容值的 block 和目标类型与 (non-void) 返回类型的组合不是潜在的候选者方法重载决议。所以你的直觉是对的,这里应该没有歧义。

模棱两可的 block 的例子是

() -> { throw new RuntimeException(); }
() -> { while (true); }

因为它们无法正常完成,但您的问题并非如此。

关于java - Lambda表达式和方法重载的疑惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23430854/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com