Hallo nochmal. Wie wir bereits geschrieben haben, wird nächste Woche eine neue Gruppe von Schulungen zum Kurs
"Java Developer" beginnen. Gemäß der etablierten Tradition werden wir Ihnen die Übersetzung von interessantem Material zu diesem Thema mitteilen.
Ab JDK 9 hat sich die Verkettung von Zeichenfolgen erheblich geändert.JEP 280 ("Indify String Concatenation") wurde als Teil von
JDK 9 implementiert und laut Abschnitt "Zusammenfassung": "Ändert die von
Javac generierte Bytecode-Sequenz für die String-Verkettung, um
aufgerufene dynamische Aufrufe von JDK-Bibliotheksfunktionen zu verwenden." Die Auswirkung auf die Zeichenfolgenverkettung in Java lässt sich am einfachsten anhand der
Javap- Ausgabe von Klassen
feststellen , die die Zeichenfolgenverkettung verwenden, die im JDK vor JDK 9 und nach JDK 9 kompiliert wurden.

Für die erste Demonstration wird eine einfache Java-Klasse namens "HelloWorldStringConcat" verwendet.
package dustin.examples; import static java.lang.System.out; public class HelloWorldStringConcat { public static void main(final String[] arguments) { out.println("Hello, " + arguments[0]); } }
Das Folgende ist ein Vergleich der Unterschiede für die -verbose-Javap-Ausgabe für die
main(String)
-Methode der HelloWorldStringConcat-Klasse beim Kompilieren mit JDK 8
(AdoptOpenJDK) und JDK 11
(Oracle OpenJDK) . Ich habe einige wichtige Unterschiede hervorgehoben.
JDK 8 Javap-Ausgabe Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcat.class Last modified Jan 28, 2019; size 625 bytes MD5 checksum 3e270bafc795b47dbc2d42a41c8956af Compiled from "HelloWorldStringConcat.java" public class dustin.examples.HelloWorldStringConcat minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
JDK 11 Javap-Ausgabe Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcat.class Last modified Jan 28, 2019; size 908 bytes MD5 checksum 0e20fe09f6967ba96124abca10d3e36d Compiled from "HelloWorldStringConcat.java" public class dustin.examples.HelloWorldStringConcat minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=1, args_size=1 0: getstatic #2
Der Abschnitt "Beschreibung" in
JEP 280 beschreibt diesen Unterschied: "Die Idee ist, den gesamten StringBuilder-Join-Tanz durch einen einfachen
invokedynamic
Aufruf von
java.lang.invoke.StringConcatFactory zu ersetzen, der Werte annimmt, die zusammengeführt werden müssen." Der gleiche Abschnitt zeigt einen ähnlichen Vergleich der kompilierten Ausgabe für ein ähnliches Beispiel für die Verkettung von Zeichenfolgen.
Die kompilierte Ausgabe mit JDK 11 zur einfachen Verkettung umfasst nicht nur weniger Zeilen als die Ausgabe von JDK 8. Er hat auch weniger "teure" Operationen. Potenzielle Leistungsverbesserungen können erzielt werden, da primitive Typen nicht umbrochen werden müssen und nicht viele zusätzliche Objekte erstellt werden müssen. Eines der Hauptmotive für diese Änderung war, "die Grundlage für die Erstellung optimierter Handler für die Verkettung von Zeichenfolgen zu legen, die implementiert werden, ohne dass der Java-zu-Bytecode-Compiler geändert werden muss" und "zukünftige Optimierungen für die Verkettung von Zeichenfolgen ohne zusätzliche Änderungen des von javac generierten Bytecodes zu ermöglichen". ""
Dies hat eine interessante Konsequenz in Bezug auf die Verwendung von
StringBuffer (für den ich ohnehin nur
schwer eine gute Verwendung finde ) und
StringBuilder . In JEP 280 in "Non-Goal" wurde angegeben, keine "neuen APIs für String und / oder StringBuilder einzuführen, die zur Erstellung effizienterer Übersetzungsstrategien beitragen könnten". In dieser Hinsicht schließt die explizite Verwendung von StringBuilder und StringBuffer für die einfache Verkettung von Zeichenfolgen, wie im Beispiel am Anfang dieses Beitrags, den Compiler praktisch von der Verwendung der in
JEP 280 eingeführten Funktion aus , die wir in diesem Beitrag diskutieren.
Die folgenden beiden Auflistungen zeigen ähnliche Implementierungen der oben gezeigten einfachen Anwendung, aber anstatt Zeichenfolgen zu verketten, verwenden sie StringBuilder bzw. StringBuffer. Wenn javap -verbose für diese Klassen ausgeführt wird, nachdem sie mit JDK 8 und mit JDK 11 kompiliert wurden, gibt es keine signifikanten Unterschiede in den Hauptmethoden (String []).
Die explizite Verwendung von StringBuilder in JDK 8 und JDK 11 ist dieselbe package dustin.examples; import static java.lang.System.out; public class HelloWorldStringBuilder { public static void main(final String[] arguments) { out.println(new StringBuilder().append("Hello, ").append(arguments[0]).toString()); } }
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuilder.class Last modified Jan 28, 2019; size 627 bytes MD5 checksum e7acc3bf0ff5220ba5142aed7a34070f Compiled from "HelloWorldStringBuilder.java" public class dustin.examples.HelloWorldStringBuilder minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuilder.class Last modified Jan 28, 2019; size 627 bytes MD5 checksum d04ee3735ce98eb6237885fac86620b4 Compiled from "HelloWorldStringBuilder.java" public class dustin.examples.HelloWorldStringBuilder minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
Die explizite Verwendung von StringBuffer in JDK 8 und JDK 11 ist dieselbe package dustin.examples; import static java.lang.System.out; public class HelloWorldStringBuffer { public static void main(final String[] arguments) { out.println(new StringBuffer().append("Hello, ").append(arguments[0]).toString()); } }
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuffer.class Last modified Jan 28, 2019; size 623 bytes MD5 checksum fdfb90497db6a3494289f2866b9a3a8b Compiled from "HelloWorldStringBuffer.java" public class dustin.examples.HelloWorldStringBuffer minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuffer.class Last modified Jan 28, 2019; size 623 bytes MD5 checksum e4a83b6bb799fd5478a65bc43e9af437 Compiled from "HelloWorldStringBuffer.java" public class dustin.examples.HelloWorldStringBuffer minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
JDK 8 und JDK 11 Umgang mit verketteten String-VerkettungenFür das letzte Beispiel für Änderungen an JEP 280 in Aktion verwende ich Beispielcode, der die Anfälligkeit einiger Java-Entwickler aufheben und Zeichenfolgen in einer Schleife verketten kann. Denken Sie daran, dass dies nur ein anschauliches Beispiel ist und alles in Ordnung ist, aber versuchen Sie nicht, es zu Hause zu wiederholen.
package dustin.examples; import static java.lang.System.out; public class HelloWorldStringConcatComplex { public static void main(final String[] arguments) { String message = "Hello"; for (int i=0; i<25; i++) { message += i; } out.println(message); } }
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcatComplex.class Last modified Jan 30, 2019; size 766 bytes MD5 checksum 772c4a283c812d49451b5b756aef55f1 Compiled from "HelloWorldStringConcatComplex.java" public class dustin.examples.HelloWorldStringConcatComplex minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: ldc #2
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcatComplex.class Last modified Jan 30, 2019; size 1018 bytes MD5 checksum 967fef3e7625965ef060a831edb2a874 Compiled from "HelloWorldStringConcatComplex.java" public class dustin.examples.HelloWorldStringConcatComplex minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: ldc #2
In der Präsentation
„Genug java.lang.String, um uns aufzuhängen ...“ diskutieren Dr.
Heinz M. Kabutz und
Dmitry Vyazelenko die Änderungen an der Java-String-Verkettung und fassen sie kurz zusammen: „+ more nicht in StringBuilder kompiliert “. Auf der Folie "Lessons from Today" heißt es: "Verwenden Sie nach Möglichkeit + anstelle von StringBuilder" und "Klassen für Java 9+ neu kompilieren".
Die in JDK 9 mit
JEP 280 implementierten Änderungen "werden es in Zukunft ermöglichen, die Verkettung von Zeichenfolgen zu optimieren, ohne dass zusätzliche Änderungen des von javac generierten Bytecodes erforderlich sind." Interessanterweise wurde kürzlich bekannt gegeben, dass JEP 348 („Java Compiler Intrinsics for JDK APIs“) jetzt ein Kandidat für JEP ist. Ziel ist es, einen ähnlichen Ansatz zum Kompilieren der Methoden
String :: format und
Objects::hash
verwenden.
Was halten Sie für einen nützlichen Artikel? Wir warten auf Ihre Kommentare und laden alle zu einem
Tag der
offenen Tür zum Java Developer-Kurs ein, der am 25. März vom Generaldirektor von OTUS -
Vitaly Chibrikov abgehalten wird .