wake-up-neo.com

Lambda Expression und generische Methode

Angenommen, ich habe eine generische Schnittstelle:

interface MyComparable<T extends Comparable<T>>  {
    public int compare(T obj1, T obj2);
}

Und eine Methode sort:

public static <T extends Comparable<T>> 
       void sort(List<T> list, MyComparable<T> comp) {
    // sort the list
}

Ich kann diese Methode aufrufen und einen Lambda-Ausdruck als Argument übergeben:

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

Das wird gut funktionieren. 

Aber jetzt, wenn ich die Schnittstelle nicht generisch und die Methode generisch mache:

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) {
}

Und dann rufen Sie folgendes auf:

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

Es wird nicht kompiliert. Es zeigt einen Fehler beim Lambda-Ausdruck: 

"Zielmethode ist generisch"

OK, wenn ich es mit javac kompiliert habe, wird folgender Fehler angezeigt:

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

Aus dieser Fehlermeldung scheint es, als könnte der Compiler nicht auf die Typargumente schließen. Ist das der Fall? Wenn ja, warum passiert das so?

Ich habe verschiedene Möglichkeiten ausprobiert und im Internet gesucht. Dann habe ich diesen JavaCodeGeeks-Artikel gefunden, der einen Weg zeigt, also habe ich versucht:

sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));

was wiederum nicht funktioniert, im Gegensatz zu dem, was der Artikel behauptet, es funktioniert. Möglicherweise funktionierte es in einigen ersten Builds.

Meine Frage ist also: Gibt es eine Möglichkeit, einen Lambda-Ausdruck für eine generische Methode zu erstellen? Ich kann dies jedoch mit einer Methodenreferenz tun, indem ich eine Methode erstellt:

public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
    return obj1.compareTo(obj2);
}

sagen Sie in einer Klasse SO und übergeben Sie es als:

sort(list, SO::compare);
97
Rohit Jain

Sie können keinen Lambda-Ausdruck für eine Funktionsschnittstelle verwenden, wenn die Methode in der Funktion ist Schnittstelle hat Typparameter . Siehe Abschnitt §15.27.3 in JLS8 :

Ein Lambda-Ausdruck ist kompatibel [..] mit einem Zieltyp [~ # ~] t [~ # ~] if [~ # ~] t [~ # ~] ist ein funktionaler Schnittstellentyp (§9.8) und der Ausdruck ist kongruent mit dem Funktionstyp von [.. ] T. [..] Ein Lambda-Ausdruck ist kongruent mit einem Funktionstyp, wenn alle der folgenden Bedingungen erfüllt sind:

  • Der Funktionstyp hat keine Typparameter .
  • [..]
106
nosid

Mit Hilfe der Methodenreferenz fand ich einen anderen Weg, um das Argument zu übergeben:

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

Zeigen Sie einfach Compiler die richtige Version des generischen Komparators mit (Comparator<String>)

Die Antwort wird also sein

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

1
Aleч

Du meinst so etwas ?:

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

Welcher Art ist das Lambda? Sie können dies nicht in Java ausdrücken und können diesen Ausdruck daher nicht in einer Funktionsanwendung zusammenstellen. Ausdrücke müssen komponierbar sein.

Damit dies funktionieren kann, benötigen Sie Unterstützung für Rank2-Typen in Java.

Methoden dürfen generisch sein, sie können sie jedoch nicht als Ausdrücke verwenden. Sie können jedoch auf den Lambda-Ausdruck reduziert werden, indem Sie alle erforderlichen generischen Typen spezialisieren, bevor Sie sie übergeben können: ClassName::<TypeName>methodName 

0
iconfly