我正在使用lambda来实现下面的Java程序中的函数接口。当lambda作为参数传递给泛型方法时,编译器会标记“不兼容类型”错误,因为它会推断出lambda表达式实现了接口,该接口将编译器将lambda参数(“thing”)解释为当lambda尝试将它传递给需要类型为Round的参数的方法(testRound)时,它的类型为Shape。这个错误对我来说很有意义。为什么lambda类型推断失败,但成功取得等价的方法引用?
但等效的方法参考不会引发错误消息。我一直在误解,一个lambda和一个可以代替lambda的方法引用是可以互换的。在这里,情况并非如此。
public class Main
{
public static void main(String... args)
{
methodB(thing -> Main.testRound(thing)); // incompatible types
methodB(Main::testRound); // no problem here
}
static <T extends Shape> void methodB(Func<T> function)
{
}
static boolean testRound(Round thing)
{
return true;
}
}
interface Func<T>
{
boolean test(T ob);
}
class Shape
{
}
class Round extends Shape
{
}
为什么当lambda失败时方法引用成功?
UPDATE
文斯Emigh找到了答案,作为接受的,下面我已标记。虽然这不是我的问题的一部分,这里有四个方法可以解决的事实,拉姆达只是推断为存在Func<Shape>
类型,如果一个人真的坚持使用lambda表达式上:
// Use a type witness.
Main.<Round>methodB(thing -> testRound(thing));
// Make the lambda's argument type explicit.
methodB((Round thing) -> testRound(thing));
// Cast the argument.
methodB(thing -> testRound((Round)thing));
// Store the lambda reference in a Func<Round> variable.
Func<Round> lambda = thing -> testRound(thing);
methodB(lambda);
我没有看到任何除非人们认为lambda稍微不密集(也许可读性更强一点),否则就更喜欢这些方法之一。但是,如果你想要他们,他们就在那里。
我可以做出的唯一假设(我仍然觉得它是一个拉伸)是:*推论发生在不同的时间*。对于lambda,'thing'被视为'T extends Shape'(一旦声明'thing'就被推断出来),而'testRound'明确需要'Round',导致错误。当使用方法引用时,参数被视为'Round',因为它是从'Main :: testRound'而不是'(T thing)'推断的。希望这是有道理的,并且记住这是基于经验而不是文档的怀疑论。我正在研究这个问题,希望得到更好的(更正式的)答案 –
@VinceEmigh,我有类似的想法,但有类似的警告。如果您发现任何问题,请告诉我。它确实令人困惑。 –
也许这样:在第一次调用时,lambda实现''Func''接口,编译器从中推断lambda的参数是'Shape'类型,并且传递'Shape 'testRound'。在第二次调用中,实现的参数类型是来自方法签名的_copied_,这里是'Round thing'。 (见JLS 15.12。3,“编译时参数类型是编译时声明[。]”的形式参数的类型)的确,这意味着其他方面相同的lambda表达式和成员引用是不可互换的。 –