web-dev-qa-db-ja.com

ラムダ式とジェネリックメソッド

私が一般的なインターフェースを持っていると仮定します:

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);
103
Rohit Jain

機能的インターフェース型パラメーターがある場合、機能的インターフェースにはラムダ式を使用できません。 JLS8のセクション§15.27. を参照してください:

ラムダ式は、ターゲットタイプと互換性があります[..] T if Tが機能的インターフェイスタイプ(§9.8)であり、式がcongruent with [..] Tの関数型[..]ラムダ式はcongruentであり、次のすべてが当てはまる場合、関数型を使用します。

  • 関数タイプには、タイプパラメータはありません
  • [..]
106
nosid

メソッド参照を使用して、引数を渡す別の方法を見つけました:

List<String> list = Arrays.asList("a", "b", "c");        
sort(list, Comparable::<String>compareTo);
16
Andrey

(Comparator<String>)を使用して、コンパイラに適切なバージョンの汎用コンパレータを指定するだけです。

だから答えは

sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));

1
Aleч

あなたはこのようなことを意味しますか?:

<T,S>(T t, S s)->...

このラムダはどのタイプですか? Javaでそれを表現できなかったため、関数アプリケーションでこの式を構成できず、式は構成可能でなければなりません。

これを機能させるには、Javaで Rank2 Types をサポートする必要があります。

メソッドはジェネリックにすることができますが、式として使用することはできません。ただし、渡す前に必要なすべてのジェネリック型を特殊化することにより、ラムダ式に縮小できます。ClassName::<TypeName>methodName

0
iconfly