Da Java8 kürzlich veröffentlicht wurde und seine brandneuen Lambda-Ausdrücke wirklich cool aussehen, habe ich mich gefragt, ob dies den Niedergang der anonymen Klassen bedeutet, an die wir so gewöhnt waren.
Ich habe ein wenig darüber recherchiert und einige coole Beispiele dafür gefunden, wie Lambda-Ausdrücke diese Klassen systematisch ersetzen, wie z. B. die Sortiermethode der Sammlung, mit der eine anonyme Instanz von Comparator die Sortierung durchführen konnte:
Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.firstName.compareTo(p2.firstName);
}
});
Jetzt kann mit Lambdas gemacht werden:
Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));
Und sieht überraschend prägnant aus. Meine Frage ist also, gibt es einen Grund, diese Klassen weiterhin in Java8 anstelle von Lambdas zu verwenden?
BEARBEITEN
Dieselbe Frage, aber in umgekehrter Richtung: Welche Vorteile bietet die Verwendung von Lambdas anstelle von anonymen Klassen, da Lambdas nur mit Schnittstellen für einzelne Methoden verwendet werden kann. Ist diese neue Funktion nur eine Verknüpfung, die nur in wenigen Fällen verwendet wird, oder ist sie wirklich nützlich?
quelle
Comparator.comparing(Person::getFirstName)
,getFirstName()
dass: eine Methode zurückgegeben wirdfirstName
.Antworten:
Eine anonyme innere Klasse (AIC) kann verwendet werden, um eine Unterklasse einer abstrakten Klasse oder einer konkreten Klasse zu erstellen. Ein AIC kann auch eine konkrete Implementierung einer Schnittstelle bereitstellen, einschließlich des Hinzufügens von Status (Feldern). Eine Instanz eines AIC kann
this
in seinen Methodenkörpern verwendet werden, sodass weitere Methoden aufgerufen werden können, sein Zustand im Laufe der Zeit mutiert werden kann usw. Keine dieser Aussagen gilt für Lambdas.Ich würde vermuten, dass die Mehrheit der Verwendungen von AICs darin bestand, zustandslose Implementierungen einzelner Funktionen bereitzustellen und daher durch Lambda-Ausdrücke ersetzt werden können, aber es gibt andere Verwendungen von AICs, für die Lambdas nicht verwendet werden können. AICs sind hier, um zu bleiben.
AKTUALISIEREN
Ein weiterer Unterschied zwischen AICs und Lambda-Ausdrücken besteht darin, dass AICs einen neuen Bereich einführen. Das heißt, Namen werden aus den Superklassen und Schnittstellen des AIC aufgelöst und können Namen beschatten, die in der lexikalisch einschließenden Umgebung auftreten. Bei Lambdas werden alle Namen lexikalisch aufgelöst.
quelle
A$1.class
Lambda jedoch nicht. Kann ich dies in Differenz hinzufügen?LambdaClass$$Lambda$1/1078694789
. Diese Klasse wird jedoch im laufenden Betrieb von der Lambda-Metafabrik generiert, nicht vonjavac
, sodass keine entsprechende.class
Datei vorhanden ist. Dies ist jedoch wiederum ein Implementierungsproblem.Lambdas ist zwar eine großartige Funktion, funktioniert aber nur mit SAM-Typen. Das heißt, Schnittstellen mit nur einer einzigen abstrakten Methode. Es würde fehlschlagen, sobald Ihre Schnittstelle mehr als eine abstrakte Methode enthält. Hier sind anonyme Klassen hilfreich.
Nein, wir können anonyme Klassen nicht einfach ignorieren. Und nur zu Ihrer Information, Ihre
sort()
Methode kann vereinfacht werden, indem Sie die Typdeklaration fürp1
und überspringenp2
:Sie können hier auch die Methodenreferenz verwenden. Entweder fügen Sie der Klasse eine
compareByFirstName()
Methode hinzuPerson
und verwenden:oder fügen Sie einen Getter hinzu
firstName
, um direkt dieComparator
from-Comparator.comparing()
Methode zu erhalten:quelle
new @MyTypeAnnotation SomeInterface(){};
. Dies ist für Lambda-Ausdrücke nicht möglich. Einzelheiten finden Sie in meiner Frage hier: Kommentieren der Funktionsschnittstelle eines Lambda-Ausdrucks .Lambda-Leistung mit anonymen Klassen
Beim Start der Anwendung muss jede Klassendatei geladen und überprüft werden.
Anonyme Klassen werden vom Compiler als neuer Subtyp für die angegebene Klasse oder Schnittstelle verarbeitet, sodass für jede Klasse eine neue Klassendatei generiert wird.
Lambdas unterscheiden sich bei der Bytecode-Generierung. Sie sind effizienter und verwenden die mit JDK7 gelieferte invokedynamic-Anweisung.
Für Lambdas wird diese Anweisung verwendet, um die Übersetzung des Lambda-Ausdrucks im Bytecode bis zur Laufzeit zu verzögern. (Anweisung wird nur zum ersten Mal aufgerufen)
Als Ergebnis wird der Lambda-Ausdruck zu einer statischen Methode (zur Laufzeit erstellt). (Es gibt einen kleinen Unterschied zu stateles und statefull Fällen, sie werden über generierte Methodenargumente aufgelöst)
quelle
invokedynamic
die im Allgemeinen langsamer alsinvokespecial
zum Erstellen neuer Instanzen anonymer Klassen verwendet wird. In diesem Sinne sind Lambdas auch langsamer (JVM kanninvokedynamic
Anrufe jedoch die meiste Zeit optimieren ).invokedynamic
Generierung von Ad-hoc-Klassen im Vergleich zu kompilierten anonymen Klassen sehr schnell.Es gibt folgende Unterschiede:
1) Syntax
Lambda-Ausdrücke sehen im Vergleich zu Anonymous Inner Class (AIC) ordentlich aus
2) Geltungsbereich
Eine anonyme innere Klasse ist eine Klasse, dh sie hat einen Bereich für Variablen, die innerhalb der inneren Klasse definiert sind.
Der Lambda-Ausdruck ist kein eigener Bereich, sondern Teil des einschließenden Bereichs.
Eine ähnliche Regel gilt für super und dieses Schlüsselwort, wenn innerhalb einer anonymen inneren Klasse und eines Lambda-Ausdrucks verwendet wird. Bei einer anonymen inneren Klasse bezieht sich dieses Schlüsselwort auf den lokalen Bereich und das Super-Schlüsselwort auf die Superklasse der anonymen Klasse. Während im Fall eines Lambda-Ausdrucks dieses Schlüsselwort auf das Objekt des umschließenden Typs verweist und super auf die Superklasse der umschließenden Klasse verweist.
3) Leistung
Zur Laufzeit erfordern anonyme innere Klassen das Laden von Klassen, die Speicherzuweisung sowie die Objektinitialisierung und den Aufruf einer nicht statischen Methode, während der Lambda-Ausdruck eine reine Aktivität zur Kompilierungszeit ist und zur Laufzeit keine zusätzlichen Kosten verursacht. Die Leistung des Lambda-Ausdrucks ist also besser als bei anonymen inneren Klassen. **
** Mir ist klar, dass dieser Punkt nicht ganz richtig ist. Weitere Informationen finden Sie in der folgenden Frage. Lambda gegen anonyme innere Klassenleistung: Reduzierung der Belastung des ClassLoader?
quelle
Lambdas in Java 8 wurde für die funktionale Programmierung eingeführt. Wo Sie Boilerplate-Code vermeiden können. Ich bin auf diesen interessanten Artikel über Lambda gestoßen.
http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html
Es ist ratsam, Lambda-Funktionen für einfache Logik zu verwenden. Wenn die Implementierung komplexer Logik mit Lambdas im Fehlerfall ein Overhead beim Debuggen des Codes ist.
quelle
Anonyme Klassen sind da, um zu bleiben, weil Lambda gut für Funktionen mit einzelnen abstrakten Methoden ist, aber in allen anderen Fällen sind anonyme innere Klassen Ihr Retter.
quelle
invoke dynamic
wird Lambda während der Kompilierungszeit nicht zurück in die anonymen Klassen konvertiert (Java muss keine Objekte erstellen, sondern muss sich nur um die Signatur der Methode kümmern, kann sich an eine Methode binden, ohne ein Objekt zu erstellenquelle