Java 8 Lambda 函数重载不明确
Java 8 Lambda Ambiguous with Overloaded Functions
我刚开始研究 Java 8 Lambda 功能。我在 Java 7 中编写了这段代码,并尝试在 lamdas 中执行它的等价物。请注意,最后一行会产生编译错误,因为重载函数不明确。我明白原因。我怎样才能用 lambda 解决这种歧义?
package com.java8.lambdas;
interface Bounceable{
void bounce(double howHigh);
}
interface Fly{
void flies(double howHigh);
}
abstract class Game{
void play(Bounceable b) {}
void play(Fly f) {}
}
class Ball extends Game{
void play(Bounceable b){ b.bounce(10); }
}
class Kite extends Game{
void play(Fly f){ f.flies(1000); }
}
public class LambdaDemo {
public static void main(String[] args) {
System.out.println("======= Java7: ========");
//Ball game
Game bg = new Ball();
bg.play(new Bounceable(){
@Override
public void bounce(double howHigh) {
System.out.println("Ball: Bouncing "+howHigh);
}
});
//Kite game
Game kg = new Kite();
kg.play(new Fly(){
@Override
public void flies(double howHigh) {
System.out.println("Kite: flies "+howHigh);
}
});
System.out.println("======= Java8 Lambdas: ========");
bg.play(x ->System.out.println("lambda: Ball bouncing "+ x)); //Ambiguous of type of Game
}
}
您可以使用类似于强制转换的语法来指示正确的类型;
// bg.Play(Bounceable)
bg.play((Bounceable) x -> System.out.println("lambda: Ball bouncing "+ x));
// kg.Play(Fly)
kg.play((Fly) x -> System.out.println("lambda: Ball bouncing "+ x));
您可以找到有关其工作原理的更多信息in this answer。
由于您的 lambda 是隐式类型的 (x -> ...),编译器需要 目标类型 来确定 lambda 的类型。它可以从方法签名中获取目标类型……通常。它必须做足够多的方法重载选择以确定是否会提供目标类型。在这种情况下,它找到了两个可能适用的方法(play(Bouncable) 和 play(Fly)),并且由于 Bouncable 和 Fly 的功能接口具有相同的数量,因此它无法根据 lambda 的数量消除其中一个。所以它不知道你打算调用哪一个,所以它不能使用方法签名来提供目标类型。
在这里您通常有多种选择来提供额外的类型信息来消除歧义;使用显式 lambda 而不是隐式 lambda,为泛型方法调用提供显式类型见证,或添加强制转换以提供显式目标类型。在这种情况下,只有最后一个——演员表——适合你。
真正的问题是这种重载对 lambda 尤其不友好。事实上,编译器会告诉您,如果您使用 -Wall 进行编译——您会在重载声明处收到一条警告,指出在使用位置会有歧义。
我刚开始研究 Java 8 Lambda 功能。我在 Java 7 中编写了这段代码,并尝试在 lamdas 中执行它的等价物。请注意,最后一行会产生编译错误,因为重载函数不明确。我明白原因。我怎样才能用 lambda 解决这种歧义?
package com.java8.lambdas;
interface Bounceable{
void bounce(double howHigh);
}
interface Fly{
void flies(double howHigh);
}
abstract class Game{
void play(Bounceable b) {}
void play(Fly f) {}
}
class Ball extends Game{
void play(Bounceable b){ b.bounce(10); }
}
class Kite extends Game{
void play(Fly f){ f.flies(1000); }
}
public class LambdaDemo {
public static void main(String[] args) {
System.out.println("======= Java7: ========");
//Ball game
Game bg = new Ball();
bg.play(new Bounceable(){
@Override
public void bounce(double howHigh) {
System.out.println("Ball: Bouncing "+howHigh);
}
});
//Kite game
Game kg = new Kite();
kg.play(new Fly(){
@Override
public void flies(double howHigh) {
System.out.println("Kite: flies "+howHigh);
}
});
System.out.println("======= Java8 Lambdas: ========");
bg.play(x ->System.out.println("lambda: Ball bouncing "+ x)); //Ambiguous of type of Game
}
}
您可以使用类似于强制转换的语法来指示正确的类型;
// bg.Play(Bounceable)
bg.play((Bounceable) x -> System.out.println("lambda: Ball bouncing "+ x));
// kg.Play(Fly)
kg.play((Fly) x -> System.out.println("lambda: Ball bouncing "+ x));
您可以找到有关其工作原理的更多信息in this answer。
由于您的 lambda 是隐式类型的 (x -> ...),编译器需要 目标类型 来确定 lambda 的类型。它可以从方法签名中获取目标类型……通常。它必须做足够多的方法重载选择以确定是否会提供目标类型。在这种情况下,它找到了两个可能适用的方法(play(Bouncable) 和 play(Fly)),并且由于 Bouncable 和 Fly 的功能接口具有相同的数量,因此它无法根据 lambda 的数量消除其中一个。所以它不知道你打算调用哪一个,所以它不能使用方法签名来提供目标类型。
在这里您通常有多种选择来提供额外的类型信息来消除歧义;使用显式 lambda 而不是隐式 lambda,为泛型方法调用提供显式类型见证,或添加强制转换以提供显式目标类型。在这种情况下,只有最后一个——演员表——适合你。
真正的问题是这种重载对 lambda 尤其不友好。事实上,编译器会告诉您,如果您使用 -Wall 进行编译——您会在重载声明处收到一条警告,指出在使用位置会有歧义。