Preis: 9,80 €
Erhältlich ab: September 2019
Umfang: 100
Lange Zeit mussten Java-Entwickler beim Formulieren von mehrzeiligen String-Literalen unschöne Umwege nehmen, während sie neidisch zu Scala, Kotlin, Groovy und anderen Sprachen schielten. Mit JEP 355 halten Textblöcke nun als Vorschau in Java 13 Einzug.
String-Literale in Java-Code zu schreiben, über mehrere Zeilen und unter Umständen mit Whitespace formatiert, ist für viele Entwickler ärgerlich. Um z. B. ein SQL Statement im Code übersichtlich über mehrere Zeilen zu formatieren, ist die Nutzung des +-Operators mit händisch eingefügten Zeilenumbrüchen am Ende üblich (Listing 1). Um festzustellen, dass die meisten Sprachen die Fähigkeit zu ordentlich formatierten String-Literalen bereits enthalten, muss man sich nur Groovy, Scala und Kotlin anschauen. Andere höhere Programmiersprachen wie C#, Swift oder Python stehen dem in nichts nach. Bei einer so hohen Anzahl an Vorbildern ist es möglich, die besten Eigenschaften der Umsetzungen für Java zu adaptieren. Das lässt sich am JEP 326 für Raw String Literals erkennen, ursprünglich für Java 12 vorgesehen. Die Community hatte viele Anmerkungen und Einwände, woraufhin der Vorschlag zurückgezogen wurde [1]. JEP 355 hat viele der Anmerkungen berücksichtigt und ermöglicht nun Entwicklern ab Java 13, auf einfache Art Multi-line-Strings im Code zu definieren. Das Feature hält im JDK 13 zunächst als Vorschau Einzug – wer es nutzen möchte, muss seinen Code also mit dem Flag --enable-preview kompilieren.
Listing 1
String statement = "SELECT\n" +
" c.id,\n" +
" c.firstname,\n" +
" c.lastName,\n" +
" c.customernumber\n" +
"FROM customers c;";
Um einige der Designentscheidungen für Text Blocks besser einordnen zu können, lohnt sich ein Blick auf den zurückgezogenen JEP 326 [2]. Dieser hatte das JDK 12 als Ziel und sah vor, Raw Strings in Java einzuführen – Zeichenfolgen, die sich über mehrere Zeilen erstrecken können und keine Escape-Sequenzen interpretieren. Um möglichst flexibel und unabhängig vom enthaltenen Text funktionieren zu können, wurde als Begrenzungssequenz eine beliebige Anzahl von Backquotes (`) vorgeschlagen. Enthält der String selbst einen Backquote, müsste die Begrenzungssequenz mindestens zwei enthalten. Enthält die Sequenz zwei aufeinanderfolgende Backquotes, hätte die Begrenzungssequenz zumindest drei usw. In der Ankündigung, dass der JEP zurückgezogen wird, erwähnt Brian Goetz einige Kritikpunkte aus der Community, die zu dieser Entscheidung geführt haben. Viele Entwickler befürchteten, die variable Anzahl an Zeichen in der Begrenzungssequenz könne für Menschen und Entwicklungsumgebungen verwirrend sein. Außerdem wurde Kritik daran laut, dass mit dem Backquote eines der wenigen unbenutzten Begrenzungszeichen im Code eingeführt wird, das damit „verbraucht“ wäre und für künftige Features nicht verwendet werden könnte. Auch die Tatsache, dass jedes mehrzeilige String-Literal mit dem vorgeschlagenen Feature automatisch auch ein Raw String sein musste, gab Anlass zu der Entscheidung, JEP 236 zurückzuziehen. Die in JEP 355 enthaltenen Ansätze bauen explizit auf den Erkenntnissen dieses Prozesses auf.
Mehrzeilige String-Literale werden von einer Sequenz aus drei Anführungszeichen (""") eingefasst. Die öffnende Zeichensequenz darf hierbei nur optional von Whitespaces und einem zwingend notwendigen Zeilenumbruch gefolgt werden. Der eigentliche Inhalt des Literals beginnt erst in der nächsten Codezeile (Listing 2). Einfache und doppelte Anführungszeichen dürfen im Literal vorkommen, ohne dass sie escapet werden müssen. Enthält das Literal selbst drei Anführungszeichen, muss mindestens eines von ihnen escapet werden.
Listing 2
String korrekterString = """ // Erstes Zeichen erst in nächster Zeile, // korrekt
{
"typ": "json",
"inhalt": "Beispieltext"
}
""";
String inkorrekterString = """{ // Zeichen nach Begrenzungssequenz, inkorrekt
"typ": "json",
"inhalt": "Beispieltext"
}
""";
Mehrzeilige String-Literale werden zur Compile-Zeit verarbeitet. Dabei geht der Compiler immer nach demselben Schema vor: Sämtliche Zeilenumbrüche in der Zeichenfolge werden zunächst betriebssystemunabhängig in einen Line Feed (\u000A) umgewandelt. Davon ausgeschlossen sind explizit mit Escape-Zeichen im Text eingetragene Sequenzen wie \n oder \r.
Im zweiten Schritt wird der Whitespace entfernt, der der Codeformatierung geschuldet ist. Gekennzeichnet wird er mit der Position der abschließenden drei Anführungszeichen. So kann man Textblöcke im Code unterbringen, dass es zur restlichen Codeformatierung passt (Listing 3). Bei Scala und Kotlin müssen mehrzeilige Literale entweder linksbündig ohne Whitespace in den Quelltext geschrieben oder mit einer Stringmanipulation von formatierungsbedingtem Whitespace befreit werden. Java hingegen orientiert sich stark an der Vorgehensweise von Swift, eine Bereinigung der Strings zur Laufzeit ist nicht nötig.
Zuletzt werden alle Escape-Sequenzen im Text interpretiert und aufgelöst. Nach dem Kompilieren ist es nicht mehr möglich, herauszufinden, wie ein String im Code definiert wurde, ob er als Multi-line-String definiert war oder nicht.
Listing 3
String string1 = """
{
"typ": "json",
"inhalt": "Beispieltext"
}
""";
// Inhalt von string1.
// Der linke Rand wird zur Veranschaulichung durch | markiert.
//|{
//| "typ": "json",
//| "inhalt": "Beispieltext"
//|}
String string2 = """
{
"typ": "json",
"inhalt": "Beispieltext"
}
""";
// Inhalt von string2.
// Der linke Rand wird zur Veranschaulichung durch | markiert.
//| {
//| "typ": "json",
//| "inhalt": "Beispieltext"
//| }
Mit den neuen Möglichkeiten, die Text Blocks für Entwickler bieten, lässt sich Code in einigen Fällen sauberer und/oder lesbarer schreiben. Wie erwähnt, ist es nun z. B. möglich, SQL Statements im Java-Code übersichtlicher darzustellen. Da Text Blocks überall verwendet werden können, wo auch herkömmliche String-Literale erlaubt sind, gilt das sogar für Named Queries mit JQL oder nativem SQL (Listing 4), die innerhalb von Annotations definiert werden.
Listing 4
@Entity
@NamedQuery(name = "findByCustomerNumberAndCity",
query = """
from Customer c
where c.customerNo = :customerNo
and c.city = :city
""")
public class CustomerEntity {
String customerNo;
String city;
public String getCustomerNo() {
return customerNo;
}
public void setCustomerNo(String customerNo) {
this.customerNo = customerNo;
}
}
Weitere sinnvolle Anwendungsfälle findet man, wenn man String-Literale als Templates nutzen möchte. Das kann entweder für JSON Payloads in Unit-Tests hilfreich sein, mit denen man einen REST Service testen möchte, oder beim serverseitigen Vorbereiten von HTML Snippets (Listing 5).
Listing 5
String htmlContent = """
<div>
<h2>My header</h2>
<ul>
<li>An entry</li>
<li>Another entry</li>
</ul>
</div>
""";
Darüber hinaus vereinfachen Textblöcke die Nutzung von polyglotten Features deutlich, sei es mit der alten Nashorn Engine oder mit dem Context der GraalVM. Der im Literal definierte JavaScript-Code wäre deutlich schlechter les- und wartbar, wenn das eingangs erwähnte Konstrukt mit Stringverkettung und manuellen Zeilenumbrüchen bemüht werden müsste (Listing 6).
Listing 6
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object result = engine.eval("""
function add(int1, int2) {
return int1 + int2;
}
add(1, 2);""");
Im Rahmen von JEP 355 werden drei neue Instanzmethoden in der Klasse String hinzugefügt: formatted, stripIndent und translateEscapes. Während formatted eine Hilfsmethode ist, die die Arbeit mit mehrzeiligen Literalen erleichtert, bilden stripIndent und translateEscapes die beiden letzten Compile-Schritte bei deren Interpretation ab.
Wie erwähnt, eignen sich Multi-line-Strings hervorragend, um Templates im Code zu definieren. Um Platzhalter in Stringtemplates mit Werten zu befüllen, existiert bereits die statische Methode format in der Klasse String. Da sich mehrzeilig definierte String-Literale in der Benutzung von einzeiligen nicht unterscheiden, können sie natürlich ebenfalls mit dieser Methode formatiert werden. Um für Textblöcke eine übersichtlichere Herangehensweise zu ermöglichen, wurde der Klasse String die neue Instanzmethode formatted spendiert, die sich analog zur statischen Methode format verhält. Das Ergebnis ist ebenfalls ein mit Platzhaltern formatierter String, in Verbindung mit Textblöcken ergibt sich aber Code, der aufgeräumter ist (Listing 7)
Listing 7
String.format("Hallo, %s, %s dich zu sehen!", "Duke", "schön");
String xmlString = """
<customer>
<no>%s</no>
<name>%s</name>
</customer>
""".formatted("12345", "Franz Kunde");
Die Methode stripIndent entfernt in mehrzeiligen Strings vorangestellten Whitespace, den alle Zeilen gemein haben, rückt also den gesamten Text nach links, ohne die Formatierung zu verändern. Die Methode translateEscapes interpretiert sämtliche Escape-Sequenzen, die in einem String enthalten sind. In Listing 8 wird dieses Verhalten noch einmal verdeutlicht.
Listing 8
// Der linke Rand wird in der Ausgabe zur Veranschaulichung durch | // markiert
String example = " a\n b\\n c";
System.out.println(example);
//| a
//| b\n c
System.out.println(example.stripIndent());
//|a
//| b\n c
System.out.println(example.translateEscapes());
//| a
//| b
//| c
System.out.println(example.stripIndent().translateEscapes());
//|a
//| b
//| c
Mit JEP 355 werden mehrzeilige String-Literale auf eine Art und Weise eingeführt, dass sie sich sowohl in ihrer Deklaration als auch in ihrer Formatierung schnell natürlich anfühlen. Die Entwickler haben hierbei von den Erfahrungen aus anderen Programmiersprachen profitiert und sich für einen Weg entschieden, der das Nachbearbeiten von Strings, etwa um störenden Whitespace zu entfernen, unnötig macht und gleichzeitig eine leserliche Formatierung von Quelltext ermöglicht. Abgerundet wird die Einführung von drei neuen Methoden in der Klasse String: formatted, stripIndent und translateEscapes. Sie ermöglichen nicht nur einen einfacheren Umgang mit den neuen Textblöcken, sondern lassen sich auch nutzen, um Strings aus anderen Quellen zu formatieren, Einrückungen zu entfernen oder Escape-Sequenzen zu interpretieren. Ich persönlich freue mich sehr auf die Einführung von Textblöcken als vollwertiges Feature und merke bei meiner Arbeit fast täglich, wie sehr mir diese momentan fehlen.
Tim Zöller arbeitet als IT Consultant bei ilum:e informatik AG in Mainz und entwickelt seit zehn Jahren Software. Er hilft Unternehmen dabei, ihre Prozesse mit Java zu digitalisieren und beschäftigt sich auch privat mit den Neuerungen in der Java-Welt. Er ist Mitgründer der Java Usergroup Mainz.
[1] https://mail.openjdk.java.net/pipermail/jdk-dev/2018-December/002402.html
Romantiker glauben heute, dass ein Piratenkodex etwas mit Richtlinien zu ehrbarem, ethischem und sozialem Verhalten an Bord eines Freibeuterkahns zu tun hatte. Fakt ist jedoch, dass die Herren der See darunter eher so etwas wie einen Arbeitsvertrag verstanden. Darin wurde unter anderem festgelegt, welche Verwundungen wie zu kompensieren waren, welche Position und Rang an Bord welche Belohnung von Beutezügen nach sich zog und welche Strafen auf welche Vergehen standen.
Ein solcher Kodex gilt auch an Bord der „Java“ unter Kapitän Oracle: Seit Version 10 gilt das Versprechen, dass die Crew (aka. die Community) pro Halbjahr einen Schatz in Form eines neuen Releases erwarten darf. Der Unterschied zu den Freibeutern der Historie: Hier bekommt jeder den gleichen Anteil, also die gleichen neuen Funktionen. In unserem Abenteuer besteht dieser Schatz, zu dem unsere Karte auf den Seiten 28–29 führt, aus fünf Kostbarkeiten, nämlich JEP 350 (Dynamic CDS Archives), JEP 351 (Uncommit Unused Memory), JEP 353 (Reimplement the Legacy Socket API), JEP 354 (Switch Expression – Revised) und JEP 355 (Text Blocks).
Long Falk Sippach hat, wie bereits in vergangenen Jahren, die Legenden um den sagenumwobenen Schatz des 13. Cpt. Duke Sparrow für uns zusammengefasst, und seine Geschichte ab Seite 20 wird jedem Schiffsjungen und alten Seeräuber das Wasser im Munde zusammenlaufen lassen. Sein Kollege Tim „Gutenbart“ Zöller hat sein Augenmerk diesmal auf die Textblöcke gelegt, die sich ebenfalls in der Schatztruhe befinden (S. 25).
Dass die 13 eine Unglückszahl ist, Freitag der 13. ein Unglückstag, und es in Tavernen oft kein Zimmer mit der Nummer 13 gibt, mag für manche darauf hinweisen, Java 13 sei möglicherweise verflucht. Den Abergläubischen sei empfohlen, eine Prise Salz über die Schulter zu werfen, sich samt Hasenpfote an den Mast zu ketten und Karsten „Sitterbeker“ Sitterbergs Artikel über Testing Frameworks (S. 66) zu lesen – Sicherheit geht schließlich vor.
Wer nicht nur sein eigenes Piratenschiff zu managen hat, sondern der Admiral einer ganzen Korsarenflotte ist, der sollte zur Ausbildung bei Calico Jo Unterstein anheuern. Der gibt mit seiner Einführung in Kubernetes Operators ab S. 78 eine gute Übersicht darüber, wie man seine Schaluppen und Galeonen und deren Ladung sicher über die wilden Ozeane lenkt und ihre Crews im Zaum hält. Im Zweifel wohl mit der Androhung des Kielholens.
Und legt man nach einer weiteren Kaperfahrt erschöpft auf der heimischen JVM an, dann trifft man sich am Strand, entzündet ein Lagerfeuer und lauscht den Enterprise Tales von Sir Hruschka & Sir Starke (S. 42) oder den DevOps Stories von Kapitän Konstantin Diener (S. 75), bevor man für das nächste Abenteuer wieder in See sticht.
Yo-ho, eine Buddel voll Rum und viel Spaß beim Lesen!
Dominik Mohilo | Redakteur
Damit blinde und sehbehinderte Menschen Software bedienen können, muss sie bestimmte Voraussetzungen erfüllen. Der hier vorgestellte barrierefreie JavaFX-Texteditor zeigt im Rahmen unserer unregelmäßig erscheinenden Toolvorstellungsreihe, wie mit Java und JavaFX eine Software entwickelt werden kann, dass sie für blinde und sehbehinderte Menschen bedienbar ist.
Marlem-Softwares barrierefreier JavaFX-Texteditor hat fast den gleichen Funktionsumfang wie der Windows-Texteditor Notepad. Auf Dialogfenster wie zum Beispiel Ersetzen oder Schriftart verzichtet der barrierefreie Texteditor, ansonsten ist er dem Windows-Tool sehr ähnlich. Das trägt dazu bei, dass Nutzer, die bisher Letzteres nutzten, eher bereit sind, umzusteigen, da sie sich an keine neue Programmoberfläche gewöhnen müssen. Alle Programmfunktionen sind über das Hauptmenü oder die Programmoberfläche erreichbar. Da blinde und viele sehbehinderte Menschen keine Computermaus bedienen können, sind sämtliche Programmfunktionen per Tastatur ausführbar. Die aufklappbaren Listen für Schriftart und Schriftgröße sind mit den Cursortasten Aufwärts und Abwärts einstellbar. Fast alle Programmfunktionen können per Shortcut ausgeführt werden, was für blinde und sehbehinderte Menschen eminent wichtig ist. Das Suchen und Ersetzen von Text kann in der Programmoberfläche ebenfalls ohne Verwendung der Maus durchgeführt werden. Zudem verfügt die Software über eine Hilfe im HTML-Format, die den Editor ausführlich erläutert und Hinweise und Code für Java-Entwickler enthält.
Nach dem Start des Texteditors ist dieser zunächst nicht barrierefrei und somit genau wie der Windows-Texteditor für Menschen ohne Behinderung nutzbar. Damit der Editor für blinde und sehbehinderte Menschen nutzbar ist, muss bei der Checkbox „Editor barrierefrei“ ein Haken gesetzt werden. Nun ändern sich zwei Dinge. Der Texteditor ist Screenreader-tauglich und für Menschen mit Sehbehinderung bedienbar. Ein Screenreader ist eine Software, die den kompletten Bildschirminhalt vorliest. Damit der Screenreader die mit JavaFX erstellte Programmoberfläche vorlesen kann, enthält sie Texte, die sie beschreiben. Damit der Screenreader die Programmoberfläche vorliest, muss der Texteditor per Tastatur bedient werden. Wird er hingegen per Maus bedient, schweigt der Screenreader, da er in diesem Fall die Benutzung durch einen blinden oder sehbehinderten User ausschließt. Durch mehrmaliges Drücken der Tabulatortaste oder durch das Ausführen von Shortcuts kann der Texteditor per Tastatur bedient werden. Als Screenreader zum Testen ist der Open-Source-Screenreader NVDA (NonVisual Desktop Access) geeignet.
Sehbehinderte Menschen haben bei der Bedienung von Software häufig Probleme, zu erkennen, welches Bedienelement gerade aktiv ist. Bei Eingabefeldern ist das besonders schwierig, da der Textcursor als senkrechter Strich dargestellt wird. Deshalb erhält das aktive Bedienelement im barrierefreien Texteditor die Hintergrundfarbe Gelb, wohingegen Bereiche, in denen Textdateien dargestellt werden, einen blauen Rahmen erhalten. So können Menschen mit Sehbehinderung erkennen, welches Bedienelement aktiv ist.
Menschen mit einer Sehbehinderung benötigen zum Bedienen einer Software große Schriften, damit sie gut lesen können, was auf dem Bildschirm zu sehen ist. In Windows kann in der Einstellung „Benutzerdefinierte Skalierung“ die Systemschriftgröße in Prozent angegeben werden. Diese Einstellung übernimmt der Texteditor, sodass auch Menschen mit einer Sehbehinderung mit dieser Software arbeiten können.
Für Menschen mit einer Farbfehlsichtigkeit lässt sich in Windows die Einstellung hoher Kontrast aktivieren. Diese wird vom JFX-Texteditor übernommen. So wird verhindert, dass das aktive Bedienelement die Hintergrundfarbe Gelb hat, da diese in Verbindung mit weißer Schrift zu einem zu geringen Farbkontrast führt. Deshalb ist hier Braun die Hintergrundfarbe des aktiven Bedienelements.
Der JFX-Texteditor läuft ab Windows 8. Außerdem sollte das Java Runtime Environment 10.0.1 installiert sein, da Barrierefreiheit in JavaFX erst nachträglich implementiert wurde.
Markus Lemcke ist seit elf Jahren selbstständig im Bereich Barrierefreiheit von Webseiten, Software und Betriebssystemen. Er ist Dozent an Hochschulen und schreibt als Autor für Fachmagazine. Sein Schwerpunkt ist die barrierefreie Softwareentwicklung mit Java und C#.