我刚开始研究Java 8 Lambda功能。我在Java 7中编写了这段代码,并尝试在lamdas中执行它。请注意,最后一行产生编译错误,因为重载的函数不明确。我理解原因。我怎样才能用lambdas解决这种歧义?
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
}
}
答案 0 :(得分:6)
您可以使用强制转换语法指示正确的类型;
// 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。
答案 1 :(得分:3)
由于lambda是一个隐式类型(x - > ...),编译器需要一个目标类型来确定lambda的类型。它通常可以从方法签名中获取目标类型。它必须做足够的方法过载选择,以确定是否会提供目标类型。在这种情况下,它找到两种可能适用的方法(播放(Bouncable)和播放(Fly)),并且由于Bouncable和Fly的功能接口具有相同的arity,因此它不能基于lambda的arity消除其中一种。因此,它不知道您打算调用哪一个,因此它不能使用方法签名来提供目标类型。
您通常会在此处提供多种选择,以提供其他类型信息以消除歧义;使用显式lambda而不是隐式lambda,为泛型方法调用提供显式类型见证,或者添加强制转换以提供显式目标类型。在这种情况下,只有最后一个 - 演员 - 将适合你。
真正的问题是这种过载特别对lambda不友好。实际上,编译器会告诉你,如果用-Wall编译 - 你会在重载声明时收到警告,表明在使用站点会有歧义。