Einrückung und Formatierung der Textblöcke
Beim vorherigen Beispiel jsonBlock heißt das, dass öffnende und schließende Klammern am Anfang ihrer jeweiligen Zeile stehen sollen, während die drei Zeilen dazwischen jeweils mit einem Tab eingerückt sind.
Um das zu ermöglichen, wendet der Compiler einen nicht uninteressanten Algorithmus an, der sich wie folgt auswirkt:
1. Alle Zwischenraumzeichen werden gleich behandelt - insbesondere ein Leerzeichen wie ein Tab.
2. Es werden aus allen nichtleeren Zeilen gleich viele führende Zwischenraumzeichen entfernt und zwar genau so viele, dass mindestens eine Zeile nicht mehr mit einem solchen Zeichen beginnt.
3. Falls die schließenden Anführungszeichen in einer eigenen Zeile stehen, wird diese im vorherigen Schritt ebenfalls berücksichtigt.
Punkt 2 führt dazu, dass das jsonBlock das gewünschte Ergebnis enthält. Denn egal wie weit der Code eingerückt ist, genau diese Einrückung wird als nebensächlich erkannt und entfernt. Was aber tun, wenn alle Zeilen eingerückt sein und zum Beispiel mit einem Tab beginnen sollen?
Einrückung variieren - durch Formatierung
Soll die Einrückung variiert werden, kommt Punkt 3 ins Spiel: Da die Zeile mit den schließenden Anführungsstrichen bei der Bestimmung der zu entfernenden Zeichen berücksichtigt wird, werden nie mehr Zwischenraumzeichen entfernt als die letzte Zeile enthält. Effektiv werden die anderen Zeilen an den schließenden Anführungsstrichen ausgerichtet. Werden sie weiter eingerückt, spiegelt sich das im Ergebnis wider.
String jsonIndentBlock = """ { greeting: "Hallo", audience: "Welt", punctuation: "!" } """;
In diesem Beispiel beginnen die sechs Zeilen, die bei der Bestimmung der Einrückung berücksichtigt werden, mit 2, 3, 3, 3, 2, bzw. 1 Tab. Der Compiler wird also einen Tab entfernen. Im Ergebnis bleiben alle anderen Zeilen mit einem Tab (öffnende und schließende Klammer) beziehungsweise zwei Tabs (restliche drei Zeilen) eingerückt.
Da man für zusätzliche Einrückung die Zeileninhalte relativ zu den schließenden Anführungsstrichen positionieren muss, bedeutet das im Umkehrschluss, dass die """ in einer eigenen Zeile stehen müssen. Wie eingangs erwähnt, hängt das einen Zeilenumbruch an das Ende des Strings. Was macht man nun, wenn man zwar die Einrückung will, aber nicht den Zeilenumbruch? Hier kommen die neuen Methoden der Klasse String ins Spiel.
Einrückung variieren - mit String-Methoden
Seit Java 12 gibt es die Methode String::indent, um alle Zeilen eines Strings mit der übergebenen Anzahl von Leerzeichen einzurücken:
String jsonIndentMethod = """ { greeting: "Hallo", audience: "Welt", punctuation: "!" }""".indent(4);
In jsonIndentMethod stehen vor der öffnenden und schließenden Klammer jeweils vier Leerzeichen. Bei den anderen drei Zeilen ist es etwas unübersichtlicher: Sie beginnen mit jeweils vier Leerzeichen plus der Einrückung entsprechend der Formatierung des Quellcodes. Ist dieser mit vier Leerzeichen eingerückt, ergibt sich das sehr gut. Sind es aber zum Beispiel zwei Leerzeichen oder ein Tab, ist die sich ergebende Einrückung etwas holprig. Eine bequeme Lösung gibt es dafür leider nicht.
Geht man aber von einer Einrückung mit vier Leerzeichen aus, ist jsonIndentMethod beinahe identisch mit jsonIndentBlock. Der einzige Unterschied ist, dass Letzterer mit einem Zeilenumbruch endet. Möchte man das nicht und braucht trotzdem Einrückung vor jeder Zeile, greift man also wie beschrieben zu String::indent.
In Java 13 wurde außerdem String::stripIndent hinzugefügt. Diese Methode entfernt Einrückungen nach genau der gleichen Logik wie der Compiler. Im folgenden String indentedJsonLiteral ist jede Zeile mit mindestens einem Tab eingerückt:
String indentedJsonLiteral = "" + " {\n" + " greeting: \"Hallo\",\n" + " audience: \"Welt\",\n" + " punctuation: \"!\"\n" + " }\n";
Der zusätzliche Tab macht indentedJsonLiteral ungleich dem einleitenden jsonBlock, aber stripIndent<String jsonBlock = """ behebt das und indentedJsonLiteral.stripIndent().equals(jsonBlock) ist wahr.
Formatierung von Textblöcken
Jim Laskey und Stuart Marks von Oracle haben einen Entwicklerleitfaden zu Textblöcken verfasst, der sehr lesenswert ist. Er enthält diese zehn Empfehlungen (leicht umformuliert und ohne die elfte):
1. Man sollte Textblöcke dort verwenden, wo sie die Lesbarkeit des Codes verbessern, also insbesondere bei mehrzeiligen Strings.
2. Wenn ein String ohne Konkatenation und Einfügen von \n in eine Zeile passt, sollte er wahrscheinlich eher als Literal definiert werden.
3. Es spricht nichts dagegen, Escape-Sequenzen wie \n in Textblöcken zu verwenden, wenn das die Lesbarkeit fördert.
4. In dem meisten Fällen sollten die drei öffnenden Anführungsstriche am Ende ihrer Zeile stehen und die drei schließenden in ihrer eigenen.
5. Textzeilen und schließende Anführungsstriche sollten nicht an den öffnenden Anführungsstrichen ausgerichtet werden.
6. Statt Textblöcke innerhalb komplexerer Ausdrücke wie Stream Pipelines zu verwenden, sind sie zugunsten der Lesbarkeit meist besser in lokalen Variablen oder statischen Konstanten aufgehoben.
7. Wegen der Gleichbehandlung von einem Tab und einem Leerzeichen sollten Textblöcke nur mit einem der beiden Zeichen eingerückt werden, um ungleichmäßige Ergebnisse zu vermeiden.
8. Wenn ein Textblock mehr als drei Anführungsstriche in Folge enthalten soll, reicht ein Escaping des jeweils ersten von drei.
9. Textzeilen sollten standardmäßig gemäß der üblichen Formatierung ausgerichtet werden.
10. Enthalten Textblöcke sehr lange Zeilen, kann horizontales Scrolling verhindert werden, indem die Zeilen ganz links ausgerichtet werden.
Damit sind neben technischen Erwägungen wie Syntax, Deduplizierung, Normalisierung der Zeilenenden und Umgang mit Einrückung auch stilistische abgedeckt. Noch etwas mehr Informationen gibt es in diesem Blogpost zu Textblöcken.
Oder nutzen Sie das Golem-pur-Angebot
und lesen Golem.de
- ohne Werbung
- mit ausgeschaltetem Javascript
- mit RSS-Volltext-Feed
Textblöcke und String-Literale sind ununterscheidbar | Was es in Java 13 sonst noch gibt |
Kurven und Graphen sind die Visualisierung von Zahlen. Symbole sind Strings der Länge 1...
Ach von Perl kommt es. OK, gut zu wissen. Für Murks halte ich es dennoch nicht, wenn es...
Ganz ehrlich: Ohne mich weiter informiert zu haben sagt mir mein Bauchgefühl auch, dass...
Danke, stimmt. Habe auch bei meinem Umstieg von Java auf C# bald gesehen wie weit hinten...
Würde vielleicht helfen, ein paar Zeilenumbrüche mit entsprechenden Einrückungen zu...