Das Switch-Statement erhält ein dringend nötiges Update, und Tee reicht Java 12 jetzt auch als Streaming-Funktion: Seit Ende März 2019 steht die zwölfte Ausgabe der Programmiersprache bereit.
Mit Java 12 schafft es Mark Reinhold das dritte Mal in Folge, eine Java-Release pünktlich vom Hof zu schaffen [1]. Nach dem als Longterm-Support-Release geadelten Vorgänger Java 11 handelt es sich nun um eine Feature-Release, die keine umwälzenden Neuerungen an Sprache oder Lizenzpolitik mit sich bringt.
Die wohl sichtbarste Änderung an Java 12: Die Entwickler haben das »switch«-Statement erweitert (Listing 1). Syntax wie Funktionsweise stammten seit Javas Anbeginn direkt aus C, was nicht alle Fans begeisterte.
Listing 1
Neuerungen für Switch
01 String var = "D";
02 // Switch im C-Stil
03 switch (var) {
04 case "A": System.out.println("C: A"); break;
05 case "B":
06 case "C": System.out.println("C: B oder C"); break;
07 case "D": System.out.println("C: D"); // Fall-Through-Fehler
08 case "E": System.out.println("C: E"); break;
09 default: System.out.println("C: Sonstiges");
10 }
11
12 // Neue Stil I, Mehrfachtreffer
13 switch (var) {
14 case "A": System.out.println("M: A"); break;
15 case "B", "C": System.out.println("M: B oder C"); break;
16 case "D": System.out.println("M: D"); // Fall-Through-Fehler
17 case "E": System.out.println("M: E"); break;
18 default: System.out.println("M: Sonstiges");
19 }
20 // Neue Stil II, kein Fall Through mehr
21 switch (var) {
22 case "A" -> System.out.println("N: A");
23 case "B", "C" -> System.out.println("N: B oder C");
24 case "D" -> System.out.println("N: D");
25 case "E" -> System.out.println("N: E");
26 default -> System.out.println("N: Sonstiges");
27 }
Zwar ist das Statement inzwischen nicht mehr nur auf Integer-Werte beschränkt, sondern kennt auch Enumerationen oder Strings. Aber ein wesentlicher Nachteil bleibt das gefährliche Fall-Through-Verhalten. Das macht das »switch«-Statement zu einem Spitzenkandidaten für Logikfehler. Ein vergessenes »break« – und schon übernimmt das Programm den Wert »D« in Zeile 7 gleich noch in Zeile 8.
Switch ließe sich als mächtiges Werkzeug nutzen, ist aber in den Styleguides einiger Firmen inzwischen ausdrücklich verboten, da im Umgang mit dem Statement zu viel zu Bruch ging. Seit Java 11 gibt es deshalb zwei Änderungen an der Grammatik, die den Code kürzer und sicherer machen sollen. So lassen sich wie in Zeile 15 gleich mehrere Gültigkeiten mit Kommas trennen. Noch sicherer ist die auch neu eingeführte Syntax mit dem »->« (Zeile 22). Mit ihr setzt der Compiler automatisch ein »break«-Statement ein. Der in Zeile 7 enthaltene Fehler passiert so nicht mehr, was die Gefahr von Logikfehlern deutlich verringert.
Das ist zwar kein umwälzendes Feature, kann aus Sicherheitserwägungen aber durchaus den Schritt von Java 11 nach Java 12 attraktiv machen. Aber Achtung: Entwickler dürfen die Syntax mit dem Doppelpunkt und dem Pfeil nicht in einem »switch«-Statement kombinieren. Zudem müssen sie die Option »–enable-preview« angeben (Abbildung 1).
Tee-Kränzchen
Neben der Sprachsyntax selbst entwickelt sich natürlich die Laufzeitbibliothek. Eine interessante Erweiterung fand im Umfeld der Streams statt. Die »teeing()«-Funktion ermöglicht es, Streams zu verzweigen und dann zusammenzuführen, wie es unter Linux der Befehl »tee« vermag. Wie Abbildung 2 zeigt, führt Java 12 den Stream dabei in zwei Kollektoren. Deren Ergebnis behandelt dann eine Funktion mit zwei Eingängen und stellt es als neuen Stream bereit.

Abbildung 2: Die »teeing()«-Funktion erlaubt es, einen Stream zu verzweigen und wieder zusammenzuführen.
Den Code dazu zeigt Listing 2. Konkret berechnet er das Verhältnis zwischen Minimal- und Maximaltemperatur. Die Temperaturwerte stehen in einem Stream bereit und werden dem Teeing-Operator zugeführt. Der nutzt die »minBy()«- und »maxBy()«-Funktionen als Kollektoren, beide geben jeweils ein »Optional<Double>« zurück.
Listing 2
Teeing
01 double ratio = Stream.of(6.1, 7.3, 7.5, 7.8, 9.8, 11.3, 11.4, 9.6, 8.6, 7.7).
02 collect( // Ergebnis einsammeln
03 teeing( // Aufteilen
04 minBy(Double::compareTo), // Pfad 1: Minimum finden
05 maxBy(Double::compareTo), // Pfad 2: Maximum finden
06 (min, max) -> min.get() / max.get() // Join Operator
07 )
08 );
09 System.out.println("verhältniss min/max " + ratio);
Die Bifunktion (Zeile 6) bekommt die beiden Rückgabewerte als Eingabewert und berechnet das Verhältnis. Die »collect()«-Funktion in Zeile 2 dient dann nur noch dazu, das Ergebnis aus dem Ausgabestream der »teeing()«-Funktion aufzusammeln. Dank der Verzweigungsmöglichkeit lassen sich so viele Auswertungen einfacher schreiben.
Fescher formatieren
Für weitere Änderungen wie das Überspringen von Bytes aus einer Datei (»InputStream.skipNBytes«) dürfte sich vermutlich nur ein Teil der Java-Anwender begeistern. Für die tägliche Arbeit erweisen sich hingegen die Formatierungs-Erweiterungen als praktisch. Da wäre zum einen die Ausgabe von Zahlen in einem kompakten, menschenlesbaren Format.
Dank »getCompactNumberInstance()« in den Zeilen 3 und 4 von Listing 3 erzeugt Java 12 eine neue Formatierung. Deren Ausgabe im kurzen und langen Format demonstriert wieder Abbildung 1. Als ebenso praktisch könnte sich auch die neue »String.indent()«-Funktion erweisen (Zeile 12), bisher mussten Entwickler das immer selbst implementieren.
Listing 3
Schöner Einrücken
01 // Ausgaben
02 System.out.println("--- Ausgaben ---");
03 NumberFormat snf = NumberFormat.getCompactNumberInstance(Locale.GERMAN, NumberFormat.Style.SHORT);
04 NumberFormat lnf = NumberFormat.getCompactNumberInstance(Locale.GERMAN, NumberFormat.Style.LONG);
05 Stream.of(1e3, 1e6, 1e9).forEach( i-> {
06 System.out.println( snf.format(i) + ", " + lnf.format(i));
07 });
08
09 System.out.println("--- Einrückung ---");
10 Stream.of(-1, 0, 2, 4, 8).forEach( i-> {
11 String s = String.format("%d", i);
12 s = s.indent(i);
13 System.out.print( s);
14 });
Fazit
Zusammenfassend bringt Java 12 nach den großen Umwälzungen in Java 10 und 11 eher kleinere Änderungen mit sich. Das neue Switch-Statement, schönere Formatierungen sowie Teeing sind dabei wohl die wesentlichen Nachrichten. Die weiteren Verbesserungen am Garbage Collector sind nett, liefern aber kaum eine Motivation zum Umstieg auf die neueste Version.
Infos
-
Open JDK 12 : http://openjdk.java.net/projects/jdk/12/







