带有重载函数的Java 8 Lambda不明确

时间:2016-04-01 17:09:14

标签: lambda java-8 overloading

我刚开始研究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

}

}

2 个答案:

答案 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编译 - 你会在重载声明时收到警告,表明在使用站点会有歧义。