我正在使用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表達式和成員引用是不可互換的。 –