Lambda表达式和方法重载疑问 [英] Lambda expression and method overloading doubts

查看:888
本文介绍了Lambda表达式和方法重载疑问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,所以方法重载是一件糟糕的事情和交易;现在已经解决了,让我们假设我实际上想要重载这样的方法:

OK, so method overloading is-a-bad-thing™. Now that this has been settled, let's assume I actually want to overload a method like this:

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

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

在Java 7中,我可以使用非模糊的匿名类轻松地调用它们参数:

In Java 7, I could call them easily with non-ambiguous anonymous classes as arguments:

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

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

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

Now in Java 8, I'd like to call those methods with lambda expressions of course, and I can!

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

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

由于编译器应该能够推断整数,为什么我不离开整数呢?

Since the compiler should be able to infer Integer, why don't I leave Integer away, then?

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

// Function
run(i -> 1);

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

But this doesn't compile. The compiler (javac, jdk1.8.0_05) doesn't like that:

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

To me, intuitively, this doesn't make sense. There is absolutely no ambiguity between a lambda expression that yields a return value ("value-compatible") and a lambda expression that yields void ("void-compatible"), as set out in the JLS §15.27.

但是,当然,JLS是深度和复杂的,我们继承了20年的向后兼容性历史,并且有新的东西,如:

But of course, the JLS is deep and complex and we inherit 20 years of backwards compatibility history, and there are new things like:


某些包含 隐式类型的lambda表达式的参数表达式 §15.27.1)或不精确的方法引用(§15.13.1)被适用性测试忽略,因为它们的含义直到a才能确定目标类型已被选中。

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.

来自JLS§15.12.2

上述限制可能与 JEP 101 未实施有关一路走来,可以看出这里此处

The above limitation is probably related to the fact that JEP 101 wasn't implemented all the way, as can be seen here and here.

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

Who can tell me exactly what parts of the JLS specifies this compile-time ambiguity (or is it a compiler bug)?

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

Bonus: Why were things decided this way?

使用jdk1.8.0_40,以上编译并正常工作

With jdk1.8.0_40, the above compiles and works fine

推荐答案

我想你找到了< a href =https://bugs.openjdk.java.net/browse/JDK-8029718>编译器中的这个错误:JDK-8029718 (或者在Eclipse中这个类似的那个:434642

比较日新闻§15.12.2.1。确定可能适用的方法


...


  • 如果满足以下所有条件,则lambda表达式(§15.27)可能与函数接口类型(§9.8)兼容:

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


  • 目标类型的函数类型的arity与lambda表达式的arity相同。

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

如果目标类型是函数类型具有void返回,然后lambda主体是语句表达式(§14.8)或void兼容块(§15.27.2)。

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).

如果目标类型的函数类型具有(非void)返回类型,则lambda主体是表达式或与值兼容的块(第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 兼容块和价值兼容块。虽然在某些情况下可能同时存在块,但部分§15.27.2。 Lambda Body 清楚地表明像() - >这样的表达式{} void 兼容块,因为它正常完成而不返回值。显而易见的是 i - > {} 也是 void 兼容块。

Note the clear distinction between "void compatible blocks" and "value-compatible blocks". While a block might be both in certain cases, the section §15.27.2. Lambda Body clearly states that an expression like () -> {} is a "void compatible block", as it completes normally without returning a value. And it should be obvious that i -> {} is a "void compatible block" too.

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

And according to the section cited above, the combination of a lambda with a block that is not value-compatible and target type with a (non-void) return type is not a potential candidate for the method overload resolution. So your intuition is right, there should be no ambiguity here.

模糊块的例子是

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

因为它们没有正常完成,但问题并非如此。

as they don’t complete normally, but this is not the case in your question.

这篇关于Lambda表达式和方法重载疑问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆