为什么 lambda 类型推断失败,但等效方法引用成功?

Why does type inference fail for lambda, but succeed for equivalent method reference?

我正在使用 lambda 在下面的 Java 程序中实现功能接口。当 lambda 作为参数传递给泛型方法时,编译器会标记一个 "incompatible types" 错误,因为它推断 lambda 实现了 Func 接口,该接口让编译器解释 lambda 参数("thing") 当 lambda 试图将它传递给需要 Round 类型参数的方法 (testRound) 时,它是 Shape 类型。这个错误对我来说很有意义。

但是等效方法引用不会引发错误消息。我一直误以为 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失败时方法引用成功?

更新

Vince Emigh 在下面找到了我已将其标记为已接受的答案。虽然这不是我的问题的一部分,但如果有人真的坚持使用 lambda,这里有四种方法可以解决 lambda 仅被推断为 Func<Shape> 类型这一事实:

// 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 的密度稍低(而且,也许可读性更高)。但是,如果您需要它们,它们就在那里。

来自JLS §15.13.2

Unlike a lambda expression, a method reference can be congruent with a generic function type (that is, a function type that has type parameters). This is because the lambda expression would need to be able to declare type parameters, and no syntax supports this; while for a method reference, no such declaration is necessary.

lambda 表达式引发错误,因为没有指定类型参数。这导致 T 被编译为 Shape(如您的 post 中所述),因为没有任何东西可以帮助推断参数的类型。

至于方法引用,由于类型可以从方法的参数中推断出来,因此不需要显式类型参数,如上面的 JLS 语句中所述。