Wenn ich eine Sammlung mit dem neuen syntaktischen Zucker von Java 8 durchlaufe, wie z
myStream.forEach(item -> {
// do something useful
});
Entspricht dies nicht dem folgenden "alten Syntax" -Schnipsel?
myStream.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
// do something useful
}
});
Bedeutet dies, dass Consumer
jedes Mal, wenn ich eine Sammlung durchlaufe , ein neues anonymes Objekt auf dem Heap erstellt wird? Wie viel Speicherplatz benötigt dies? Welche Auswirkungen auf die Leistung hat es? Bedeutet das, dass ich beim Durchlaufen großer mehrstufiger Datenstrukturen lieber den alten Stil für Schleifen verwenden sollte?
Antworten:
Es ist gleichwertig, aber nicht identisch. Einfach gesagt, wenn ein Lambda-Ausdruck keine Werte erfasst, ist er ein Singleton, der bei jedem Aufruf wiederverwendet wird.
Das Verhalten ist nicht genau angegeben. Der JVM wird große Freiheit bei der Implementierung eingeräumt. Derzeit erstellt die JVM von Oracle (mindestens) eine Instanz pro Lambda-Ausdruck (dh teilt die Instanz nicht zwischen verschiedenen identischen Ausdrücken), sondern erstellt Singletons für alle Ausdrücke, die keine Werte erfassen.
Sie können diese Antwort für weitere Details lesen . Dort gab ich nicht nur eine detailliertere Beschreibung, sondern testete auch Code, um das aktuelle Verhalten zu beobachten.
Dies wird in der Java®-Sprachspezifikation, Kapitel „ 15.27.4. Laufzeitauswertung von Lambda-Ausdrücken “
Zusammenfassend:
quelle
Wann eine Instanz, die das Lambda darstellt, sensibel erstellt wird, hängt vom genauen Inhalt des Körpers Ihres Lambda ab. Der Schlüsselfaktor ist nämlich, was das Lambda aus der lexikalischen Umgebung erfasst . Wenn kein Status erfasst wird, der von Erstellung zu Erstellung variabel ist, wird nicht jedes Mal eine Instanz erstellt, wenn die for-each-Schleife eingegeben wird. Stattdessen wird zur Kompilierungszeit eine synthetische Methode generiert, und die Lambda-Verwendungssite empfängt nur ein Singleton-Objekt, das an diese Methode delegiert.
Beachten Sie außerdem, dass dieser Aspekt von der Implementierung abhängt und Sie mit zukünftigen Verbesserungen und Weiterentwicklungen von HotSpot in Richtung höherer Effizienz rechnen können. Es gibt allgemeine Pläne, z. B. ein leichtes Objekt ohne eine vollständige entsprechende Klasse zu erstellen, die gerade genug Informationen enthält, um an eine einzelne Methode weitergeleitet zu werden.
Hier ist ein guter, zugänglicher ausführlicher Artikel zum Thema:
http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
quelle
Sie übergeben eine neue Instanz an die
forEach
Methode. Jedes Mal, wenn Sie dies tun, erstellen Sie ein neues Objekt, jedoch nicht eines für jede Schleifeniteration. Die Iteration erfolgt innerhalb derforEach
Methode mit derselben 'Callback'-Objektinstanz, bis sie mit der Schleife durchgeführt wird.Der von der Schleife verwendete Speicher hängt also nicht von der Größe der Sammlung ab.
Ja. Es hat leichte Unterschiede auf einem sehr niedrigen Niveau, aber ich denke nicht, dass Sie sich um sie kümmern sollten. Lamba-Ausdrücke verwenden die Funktion invokedynamic anstelle von anonymen Klassen.
quelle