私が一般的なインターフェースを持っていると仮定します:
interface MyComparable<T extends Comparable<T>> {
public int compare(T obj1, T obj2);
}
メソッドsort
:
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}
このメソッドを呼び出して、ラムダ式を引数として渡すことができます。
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
それはうまくいきます。
しかし、インターフェイスを非ジェネリックにし、メソッドをジェネリックにすると:
interface MyComparable {
public <T extends Comparable<T>> int compare(T obj1, T obj2);
}
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable comp) {
}
そして、これを次のように呼び出します:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
コンパイルしません。ラムダ式でのエラーを示しています:
「ターゲットメソッドはジェネリック」
OK、javac
を使用してコンパイルすると、次のエラーが表示されます。
SO.Java:20: error: incompatible types: cannot infer type-variable(s) T#1
sort(list, (a, b) -> a.compareTo(b));
^
(argument mismatch; invalid functional descriptor for lambda expression
method <T#2>(T#2,T#2)int in interface MyComparable is generic)
where T#1,T#2 are type-variables:
T#1 extends Comparable<T#1> declared in method <T#1>sort(List<T#1>,MyComparable)
T#2 extends Comparable<T#2> declared in method <T#2>compare(T#2,T#2)
1 error
このエラーメッセージから、コンパイラは型引数を推測できないようです。そうですか?はいの場合、なぜこのようになっているのですか?
私はさまざまな方法を試し、インターネットで検索しました。それから このJavaCodeGeeksの記事 が見つかりました。
sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));
この記事が機能していると主張していることとは反対に、これも機能しません。いくつかの初期ビルドで使用されていた可能性があります。
だから私の質問は:ジェネリックメソッドのラムダ式を作成する方法はありますか?メソッドを作成することで、メソッド参照を使用してこれを行うことができます:
public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
一部のクラスではSO
と言い、次のように渡します。
sort(list, SO::compare);
機能的インターフェースに型パラメーターがある場合、機能的インターフェースにはラムダ式を使用できません。 JLS8のセクション§15.27. を参照してください:
ラムダ式は、ターゲットタイプと互換性があります[..] T if Tが機能的インターフェイスタイプ(§9.8)であり、式がcongruent with [..] Tの関数型[..]ラムダ式はcongruentであり、次のすべてが当てはまる場合、関数型を使用します。
- 関数タイプには、タイプパラメータはありません。
- [..]
メソッド参照を使用して、引数を渡す別の方法を見つけました:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, Comparable::<String>compareTo);
(Comparator<String>)
を使用して、コンパイラに適切なバージョンの汎用コンパレータを指定するだけです。
だから答えは
sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));
あなたはこのようなことを意味しますか?:
<T,S>(T t, S s)->...
このラムダはどのタイプですか? Javaでそれを表現できなかったため、関数アプリケーションでこの式を構成できず、式は構成可能でなければなりません。
これを機能させるには、Javaで Rank2 Types をサポートする必要があります。
メソッドはジェネリックにすることができますが、式として使用することはできません。ただし、渡す前に必要なすべてのジェネリック型を特殊化することにより、ラムダ式に縮小できます。ClassName::<TypeName>methodName