2015-02-05 5 views
6

Ich habe nur immer verwendet Java 6 und jetzt bin Aufholjagd zu erfahren, was in Java 8. Neues ich diesen Artikel las hier: http://www.drdobbs.com/jvm/lambda-expressions-in-java-8/240166764?pgno=2Können BiFunction-Referenzen an Methoden übergeben werden, die eine funktionale Schnittstelle erwarten?

Und er sagt:

Die Java-API definiert mehrere generische funktionale Schnittstellen im Paket java.util.function. Eine der Schnittstellen, bifunktionellen, beschreibt Funktionen mit Parametertypen T und U und Rückgabetyp R. Sie können unsere String-Vergleich Lambda in einer Variable dieses Typ speichern:

bifunktionellen comp = (erste, zweite) -> Integer.compare (first.length(), second.length());

Das hilft Ihnen jedoch nicht beim Sortieren. Dort ist ist keine Arrays.sort Methode, die eine BiFunction will. Wenn Sie zuvor eine funktionale Programmiersprache verwendet haben, können Sie dies merkwürdig finden. Aber für Java-Programmierer, es ist ziemlich natürlich. Eine Schnittstelle wie Comparator hat einen bestimmten Zweck, nicht nur eine Methode mit gegebenen Parameter und Rückgabetypen. Java 8 behält diesen Geschmack. Wenn Sie wollen, dass etwas mit Lambda-Ausdrücken macht, wollen Sie immer noch den Zweck des Ausdrucks im Hinterkopf behalten und eine spezifische funktionale Schnittstelle dafür haben.

Allerdings, wenn ich diesen Thread sehen: How do you assign a lambda to a variable in Java 8?

Die Antworten auf die Frage legen nahe, es zu tun genau das, was der zitierte Absatz sagt man nicht tun kann.

Also, ist die Information in dem Artikel falsch, oder bin ich hier etwas falsch?

Danke!

+2

Sie könnten einfach das gleiche Lambda einem 'Comparator' zuweisen und es in einem Sortieraufruf verwenden ... –

Antwort

16

Ich sehe nichts in der verknüpften SO Antwort, die dem Artikel widerspricht.

Reguläre Regeln des Typsystems gelten für Objekte funktionaler Schnittstellentypen.Wenn Sie eine Variable als BiFunction<String,String,Integer> bifunc deklarieren, können Sie sie nicht an eine Methode übergeben, die Comparator<String> erfordert, da BiFunction<String,String,Integer> kein Untertyp von Comparator<String> ist.

Die Tatsache, dass Funktionstypen allen üblichen Regeln folgen, erlaubte es, diese neue Funktionalität mit minimalen Störungen hinzuzufügen.

Und wenn Sie ein Comparator aus einem BiFunction alles, was Sie tun müssen, machen wollen, ist ::apply hinzufügen wie folgt:

BiFunction<String,String,Integer> bifunc = (a,b) -> 
           Integer.compare(a.length(), b.length()); 

Arrays.sort(array, bifunc::apply); 
2

Der Artikel ist korrekt in dem Sinne, dass Sie nicht basierend auf Objekt von BiFunction Typ sortieren können, aber Sie können immer Comparator verwenden. Aber hey, beide können den gleichen Körper haben. Zum Beispiel:

private static void sort(Comparator<String> ls){ 
     Arrays.sort(someArray, ls); 
} 

Comparator<String> comp = (String f1, String f2) -> Integer.compare(f1.length(), f2.length()); 
sort(comp); 

BiFunction<String, String, Integer> func = (String f1, String f2) -> Integer.compare(f1.length(), f2.length()); 
sort((String f1, String f2) -> Integer.compare(f1.length(), f2.length())); //line-4 

sort(func) // compiler error 

oben an der Linie-4, sind Sie in der Lage einen Lambda passieren, die als func genau gleich ist. Aber Sie können immer noch nicht func zu sort übergeben. Lambdas in Java8 sind eine Implementierung von einigen FunctionalInterface. Funktionsschnittstellen erhalten ihren Typ basierend auf ihrem Referenztyp. So kann das gleiche Lambda bei der Initialisierung entweder BiFunction oder Comparator sein.

Aber sobald ein Lambda aufgebaut ist und es seinen Typ bekommt, kann man es nicht ändern. Daher können Sie nicht übergeben func des Typs BiFunction zu sortieren, was erwartet Comparator

1

Der Artikel korrekt ist. Sie können z. a BiFunction zu einem Comparator.

Mit diesem gesagt, dieses great article geschrieben von Brian Goetz erklärt das Problem auf eine nette Art und Weise.

Wenn der Compiler einen Lambda-Ausdruck trifft, es zuerst absenkt (desugars) der Lambda-Körper in eine Methodenliste, deren Argument und das Rück diese Art Spiel der Lambda-Ausdruck

So kann eine Lambda sein desugared - aber was bedeutet das? Nun, im Grunde bedeutet das, dass eine neue Methode (möglicherweise) erstellt wird, die irgendwie mit der Lamdba übereinstimmt.

class A { 
    public void foo() { 
     List<String> list = ... 
     list.forEach([lambda for lambda$1 as Consumer]); 
    } 

    static void lambda$1(String s) { 
     System.out.println(s); 
    } 
} 

im Falle des BiFunction und Comparator Also:

class A { 
    public void foo() { 
     List<String> list = ... 
     list.forEach(s -> { System.out.println(s); }); 
    } 
} 

Der obige Code wird zu so etwas wie dieses entzuckert sein.

// Assign the lambda to a BiFunction 
BiFunction<String, String, Integer> b1 = 
     (first, second) -> Integer.compare(first.length(), second.length()); 

// Assign the lambda to a Comparator 
Comparator<String> c1 = 
     (first, second) -> Integer.compare(first.length(), second.length()); 

// But, once the lambda has been assigned to a type you can not reassign it 
BiFunction<String, String, Integer> b2 = c1; // <-- Error 

Beachten Sie, dass einmal eine Lambda hat zu einer Art zugeordnet worden (BiFunction oder Comparator), dann kann es nicht neu zugewiesen werden, auch wenn der Lambda-Ausdruck entspricht: Das bereitgestellten Lambda kann sowohl zugeordnet werden.

+0

Wenn Sie Code-Snippets aus diesem alten Artikel übernehmen, sollten Sie die Chance nutzen, sie auf die tatsächliche API zu aktualisieren. Was damals "Block " hieß, wurde zu "Consumer ". Sich mit den alten Namen zu beschäftigen, kann für Leser, die sich der Geschichte nicht bewusst sind, verwirrend sein. – Holger

+0

@Holger noch einmal, danke. Die Antwort wurde aktualisiert. – wassgren

Verwandte Themen