Lambda 表达式和方法重载疑问
好吧,所以方法重载是一件™坏事。现在已经解决了这个问题,让我们假设我实际上想要重载这样一个方法:
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 表达式和生成返回值的 lambda 表达式(“void 兼容”)之间绝对没有歧义,如 JLS §15.27 中所述。void
但是,当然,JLS是深刻而复杂的,我们继承了20年的向后兼容性历史,并且有一些新的东西,例如:
适用性测试会忽略某些包含隐式类型的 lambda 表达式 (§15.27.1) 或不精确方法引用 (§15.13.1) 的参数表达式,因为在选择目标类型之前无法确定它们的含义。
上述限制可能与JEP 101没有完全实现的事实有关,如这里和这里所示。
问题:
谁能确切地告诉我JLS的哪些部分指定了这种编译时的歧义(或者它是编译器错误)?
奖励:为什么事情是这样决定的?
更新:
使用jdk1.8.0_40,上述编译并正常工作