【问题标题】:Java 8 Lambda Ambiguous with Overloaded Functions重载函数的 Java 8 Lambda 模棱两可
【发布时间】:2016-04-01 17:09:13
【问题描述】:

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

}

}

【问题讨论】:

  • 看看这个question。那是您的问题的副本。我没有全部阅读,但最终看来,您尝试做的事情是不可能的。使用泛型是一种解决方法,但可能并不理想。

标签: lambda java-8 overloading


【解决方案1】:

您可以使用类似强制转换的语法来指示正确的类型;

// 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 找到有关其工作原理的更多信息。

【讨论】:

    【解决方案2】:

    由于您的 lambda 是一个隐式类型 (x -> ...),编译器需要一个 目标类型 来确定 lambda 的类型。它可以从方法签名中获取目标类型……通常。它必须做足够的方法重载选择来确定是否会提供目标类型。在这种情况下,它找到了两个可能适用的方法(play(Bouncable) 和 play(Fly)),并且由于 Bouncable 和 Fly 的函数接口具有相同的元数,它无法根据 lambda 的元数消除其中一个。所以它不知道你要调用哪一个,所以它不能使用方法签名来提供目标类型。

    您通常有多种选择来提供额外的类型信息以消除歧义;使用显式 lambda 而不是隐式 lambda,为泛型方法调用提供显式类型见证,或添加强制转换以提供显式目标类型。在这种情况下,只有最后一个——演员阵容——对你有用。

    真正的问题是这种重载对 lambda 不友好。实际上,编译器会告诉您,如果您使用 -Wall 进行编译,您将在声明重载时收到警告,指出使用站点将存在歧义。

    【讨论】:

    • 在这种情况下,#1 不起作用,因为你实现的函数的参数类型不是Fly,在FlyBounceable 的情况下都是double
    • @JoachimIsaksson 谢谢,已修复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    相关资源
    最近更新 更多