Haben Lambda-Ausdrücke eine andere Verwendung als das Speichern von Codezeilen?
Gibt es spezielle Funktionen von Lambdas, die Probleme lösten, die nicht einfach zu lösen waren? Die typische Verwendung, die ich gesehen habe, ist die, anstatt dies zu schreiben:
Comparator<Developer> byName = new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getName().compareTo(o2.getName());
}
};
Wir können einen Lambda-Ausdruck verwenden, um den Code zu verkürzen:
Comparator<Developer> byName =
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName());
(o1, o2) -> o1.getName().compareTo(o2.getName())
Comparator.comparing(Developer::getName)
Antworten:
Lambda-Ausdrücke ändern nicht die Probleme, die Sie mit Java im Allgemeinen lösen können, erleichtern jedoch definitiv die Lösung bestimmter Probleme, nur aus dem gleichen Grund, aus dem wir nicht mehr in Assemblersprache programmieren. Das Entfernen redundanter Aufgaben aus der Arbeit des Programmierers erleichtert das Leben und ermöglicht es, Dinge zu tun, die Sie sonst nicht einmal berühren würden, nur für die Menge an Code, die Sie (manuell) produzieren müssten.
Lambda-Ausdrücke speichern jedoch nicht nur Codezeilen. Mit Lambda-Ausdrücken können Sie Funktionen definieren , für die Sie zuvor anonyme innere Klassen als Problemumgehung verwenden konnten. Deshalb können Sie in diesen Fällen anonyme innere Klassen ersetzen, jedoch nicht generell.
Insbesondere werden Lambda-Ausdrücke unabhängig von der Funktionsschnittstelle definiert, in die sie konvertiert werden, sodass keine geerbten Mitglieder vorhanden sind, auf die sie zugreifen können. Außerdem können sie nicht auf die Instanz des Typs zugreifen, der die Funktionsschnittstelle implementiert. Siehe auch diese Antwort innerhalb eines Lambda-Ausdrucks
this
undsuper
mit derselben Bedeutung wie im umgebenden Kontext . Sie können auch keine neuen lokalen Variablen erstellen, die lokale Variablen des umgebenden Kontexts überschatten. Für die beabsichtigte Aufgabe, eine Funktion zu definieren, werden viele Fehlerquellen entfernt, aber es wird auch impliziert, dass es für andere Anwendungsfälle anonyme innere Klassen geben kann, die nicht in einen Lambda-Ausdruck konvertiert werden können, selbst wenn eine funktionale Schnittstelle implementiert wird.Darüber hinaus
new Type() { … }
garantiert das Konstrukt (wienew
immer) , eine neue eindeutige Instanz zu erzeugen . Anonyme Instanzen der inneren Klasse behalten immer einen Verweis auf ihre äußere Instanz, wenn sie in einem Nicht-static
Kontext erstellt werden. Im Gegensatz dazu erfassen Lambda-Ausdrücke nur dann einen Verweis,this
wenn dies erforderlich ist, dh wenn sie darauf zugreifenthis
oder nichtstatic
Mitglied sind. Und sie erzeugen Instanzen einer absichtlich nicht spezifizierten Identität, wodurch die Implementierung zur Laufzeit entscheiden kann, ob vorhandene Instanzen wiederverwendet werden sollen (siehe auch „ Erstellt ein Lambda-Ausdruck bei jeder Ausführung ein Objekt auf dem Heap? “).Diese Unterschiede gelten für Ihr Beispiel. Ihr anonymes inneres Klassenkonstrukt erzeugt immer eine neue Instanz. Außerdem erfasst es möglicherweise einen Verweis auf die äußere Instanz, während es sich bei Ihrem
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName())
nicht erfassenden Lambda-Ausdruck um einen Singleton handelt, der in typischen Implementierungen als Singleton ausgewertet wird. Außerdem wird keine.class
Datei auf Ihrer Festplatte erstellt.Angesichts der Unterschiede sowohl in Bezug auf die Semantik als auch in Bezug auf die Leistung können Lambda-Ausdrücke die Art und Weise verändern, wie Programmierer bestimmte Probleme in Zukunft lösen werden, natürlich auch aufgrund der neuen APIs, die Ideen der funktionalen Programmierung unter Verwendung der neuen Sprachfunktionen enthalten. Siehe auch Java 8 Lambda-Ausdruck und erstklassige Werte .
quelle
Programmiersprachen können nicht von Maschinen ausgeführt werden.
Sie sind für Programmierer gedacht .
Sprachen sind ein Gespräch mit einem Compiler, um unsere Gedanken in etwas zu verwandeln, das eine Maschine ausführen kann. Eine der wichtigsten Beschwerden über Java von Menschen , die aus anderen Sprachen zu ihm kommen (oder lassen es für andere Sprachen) verwendet sein , dass es zwingt ein gewisses mentales Modell auf dem Programmiergerät (dh alles ist eine Klasse).
Ich werde nicht abwägen, ob das gut oder schlecht ist: Alles ist ein Kompromiss. Mit Java 8-Lambdas können Programmierer jedoch in Funktionen denken , was in Java bisher nicht möglich war.
Es ist dasselbe wie ein prozeduraler Programmierer, der lernt, in Klassen zu denken , wenn sie zu Java kommen: Sie sehen, wie sie sich allmählich von Klassen entfernen, die verherrlichte Strukturen sind und 'Helfer'-Klassen mit einer Reihe statischer Methoden haben, und zu etwas übergehen, das ähnelt eher einem rationalen OO-Design (mea culpa).
Wenn Sie sie nur als eine kürzere Möglichkeit betrachten, anonyme innere Klassen auszudrücken, werden Sie sie wahrscheinlich nicht so beeindruckend finden, wie der oben beschriebene prozedurale Programmierer wahrscheinlich nicht dachte, dass Klassen eine große Verbesserung darstellen.
quelle
Das Speichern von Codezeilen kann als neue Funktion angesehen werden, wenn Sie damit einen wesentlichen Teil der Logik kürzer und klarer schreiben können, was für andere weniger Zeit zum Lesen und Verstehen benötigt.
Ohne Lambda-Ausdrücke (und / oder Methodenreferenzen)
Stream
wären Pipelines viel weniger lesbar gewesen.Stellen Sie sich zum Beispiel vor, wie die folgende
Stream
Pipeline ausgesehen hätte, wenn Sie jeden Lambda-Ausdruck durch eine anonyme Klasseninstanz ersetzt hätten.Es wäre:
Dies ist viel schwieriger zu schreiben als die Version mit Lambda-Ausdrücken und viel fehleranfälliger. Es ist auch schwerer zu verstehen.
Und das ist eine relativ kurze Pipeline.
Um dies ohne Lambda-Ausdrücke und Methodenreferenzen lesbar zu machen, hätten Sie Variablen definieren müssen, die die verschiedenen hier verwendeten funktionalen Schnittstelleninstanzen enthalten, wodurch die Logik der Pipeline aufgeteilt und das Verständnis erschwert worden wäre.
quelle
Comparator
fürsorted
da es ohnehin in natürlicher Ordnung vergleicht. Vielleicht ändern Sie es, um die Länge von Zeichenfolgen oder ähnliches zu vergleichen, um das Beispiel noch besser zu machen?compareToIgnoreCase
um es anders zu machen verhalten alssorted()
.compareToIgnoreCase
ist immer noch ein schlechtes Beispiel, da Sie einfach den vorhandenenString.CASE_INSENSITIVE_ORDER
Komparator verwenden könnten . Der Vorschlag von @ tobias_k, nach Länge zu vergleichen (oder jede andere Eigenschaft, die keinen eingebauten Komparator hat), passt besser. Nach SO Q & A-Codebeispielen zu urteilen, verursachten Lambdas viele unnötige Komparatorimplementierungen…Interne Iteration
Wenn Java Collections iterieren, neigen die meisten Entwickler zu bekommen , ein Element und dann verarbeiten sie. Nehmen Sie das Element heraus und verwenden Sie es dann oder fügen Sie es erneut ein usw. Mit Java-Versionen vor 8 können Sie eine innere Klasse implementieren und Folgendes tun:
Mit Java 8 können Sie jetzt besser und weniger ausführlich vorgehen mit:
oder besser
Verhalten als Argumente
Erraten Sie den folgenden Fall:
Mit der Java 8 Predicate-Oberfläche können Sie Folgendes besser tun:
Nennen wir es wie:
Quelle: DZone - Warum wir Lambda-Ausdrücke in Java benötigen
quelle
numbers.forEach((Integer value) -> System.out.println(value));
der Lambda-Ausdruck aus zwei Teilen, dem linken links neben dem Pfeilsymbol (->), in dem die Parameter aufgeführt sind, und dem rechten Teil , der den Körper enthält . Der Compiler stellt automatisch fest, dass der Lambda-Ausdruck dieselbe Signatur wie die einzige nicht implementierte Methode der Consumer-Schnittstelle hat.Es gibt viele Vorteile der Verwendung von Lambdas anstelle der folgenden inneren Klasse:
Machen Sie den Code kompakter und ausdrucksvoller, ohne mehr Sprachsyntax-Semantik einzuführen. Sie haben in Ihrer Frage bereits ein Beispiel gegeben.
Durch die Verwendung von Lambdas können Sie gerne mit funktionalen Operationen an Elementströmen programmieren, z. B. Transformationen mit Kartenreduzierung für Sammlungen. Siehe Dokumentation zu den Paketen java.util.function & java.util.stream .
Es gibt keine physische Klassendatei, die vom Compiler für Lambdas generiert wurde. Dadurch werden Ihre gelieferten Anwendungen kleiner. Wie weist Memory Lambda zu?
Der Compiler optimiert die Lambda-Erstellung, wenn das Lambda nicht auf Variablen außerhalb seines Gültigkeitsbereichs zugreift. Dies bedeutet, dass die Lambda-Instanz nur einmal von der JVM erstellt wird. Weitere Informationen finden Sie in der Antwort von @ Holger auf die Frage. Ist das Zwischenspeichern von Methodenreferenzen in Java 8 eine gute Idee? .
Lambdas kann neben der funktionalen Schnittstelle auch Multi-Marker-Schnittstellen implementieren, aber die anonymen inneren Klassen können keine weiteren Schnittstellen implementieren, zum Beispiel:
quelle
Lambdas sind nur syntaktischer Zucker für anonyme Klassen.
Vor Lambdas können anonyme Klassen verwendet werden, um dasselbe zu erreichen. Jeder Lambda-Ausdruck kann in eine anonyme Klasse konvertiert werden.
Wenn Sie IntelliJ IDEA verwenden, kann es die Konvertierung für Sie durchführen:
quelle
Um Ihre Frage zu beantworten, können Sie mit Lambdas nichts tun, was Sie vor Java-8 nicht konnten, sondern Sie können präziseren Code schreiben . Dies hat den Vorteil, dass Ihr Code klarer und flexibler wird.
quelle
Eine Sache, die ich noch nicht erwähnt habe, ist, dass Sie mit einem Lambda die Funktionalität dort definieren können, wo sie verwendet wird .
Wenn Sie also eine einfache Auswahlfunktion haben, müssen Sie diese nicht an einem separaten Ort mit einem Bündel Boilerplate platzieren. Sie schreiben einfach ein Lambda, das präzise und lokal relevant ist.
quelle
Ja, es gibt viele Vorteile.
quelle