ラムダを使用して、以下のJavaプログラムで機能インタフェースを実装しています。ラムダが汎用メソッドの引数として渡されるとき、ラムダがFunc <シェイプ>インターフェイスを実装することを推測するため、コンパイラは "互換性のない型"エラーをフラグに設定します。ラムダがRound型の引数を必要とするメソッド(testRound)にラムダが渡そうとすると、Shape型になります。そのエラーは私には意味をなさない。ラムダの型推論はなぜ失敗しますが、それと同等のメソッド参照が成功するのはなぜですか?
しかし、同等のメソッド参照ではエラーメッセージが表示されません。私は、そのラムダを置き換えることができるラムダとメソッド参照が交換可能であるという誤解の下にいました。ここではそうではありません。
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
{
}
なぜラムダが失敗した場合にメソッド参照が成功するのですか?
UPDATE
ヴィンスEmighは、私は以下、受け入れとしてマークされてきた答えを見つけました。
// 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);
私は表示されません。それは私の質問の一部ではないですが、ここでラムダは一つだけが実際に使用してラムダに貼り付けた場合のタイプFunc<Shape>
であるとして推定されているという事実を回避するには、次の4つの方法がありますラムダが少し密度が低いと感じる人がいない限り、メソッドリファレンスよりもこれらのうちの1つを好む理由です。しかし、あなたがそれらを望むなら、彼らはそこにいます。
私が作ることができる唯一の仮定(まだ私はストレッチであると感じます)は次のとおりです:*推論は異なる時に起こっています*。ラムダの場合、 'thing'は(' thing'が宣言されるとすぐに推論される) 'T extends Shape'と見なされ、' testRound'は明示的に 'Round'を必要とし、エラーを引き起こします。メソッド参照を使うとき、 '(T thing)'ではなく 'Main :: testRound'から推論されているので、引数は' Round'と見なされます。これが意味をなさないことを願って、これはドキュメンテーションではなく経験に基づく懐疑論であることに留意してください。私はより良い(より公式な)答えを得るためにこれを検討しています –
@ VinceEmigh、私は同様の警告と多少類似した考えを持っていました。あなたが何かを見つけたら教えてください。確かに困惑している。 –
多分:最初の呼び出しで、lambdaは 'Func'インタフェースを実装します。このインタフェースから、ラムダへの引数は 'Shape'型であるとコンパイラが推測します。' Shape 'testRound'に渡します。 2回目の呼び出しでは、実装の引数型は、メソッドのシグネチャから_copied_、ここでは「Round thing」です。 (JLS 15.12を参照のこと。コンパイル時のパラメータ型は、コンパイル時宣言[。]の仮パラメータの型です)実際には、これはそうでなければ同じラムダを意味し、メンバ参照は互換性がありません。 –