Java 9 - The whole nine yards?!

Mitte September wurde Java 9 offiziell released. Wie schon bei Java 8 werden auch bei Java 9 einige Ideen aufgegriffen und in den Standardumfang übernommen, die so oder so ähnlich schon aus der Community bereitgestellt wurden. Wir stellen die unserer Meinung nach relevantesten Features für den täglichen Gebrauch vor.

Mehr Ordnung beim Puzzlespiel

Die wohl bekannteste Neuerung dabei ist das Java Platform Module System (JPMS) besser bekannt unter dem Namen Jigsaw. Bisher war es so: Wer kein OSGi genutzt hat, Stand bei der Auslieferung der Software immer vor zwei hausgemachten Java-Problemen: Zum einen konnte alles was in einem JAR enthalten war von außen auch benutzt werden. Zum anderen kam es zu Konflikten mit unvorhersehbarem Verhalten, wenn man zwei JARs in unterschiedlicher Version gleichzeitig im Classpath hatte. Mit Java 9 und dem JPMS gehören diese Probleme der Vergangenheit an. Es kann nun für jedes Modul definiert werden, welche seiner Packages es nach außen zur Verfügung stellt, und welche anderen Module es in welcher Version benötigt.  Das sorgt für mehr Ordnung und stabileres Laufzeitverhalten.

Die Umsetzung in den IDEs ist unterschiedlich weit fortgeschritten. Während in IntelliJ ab Version 2017.1 den Entwickler hier bereits mit Auto-Adding und Autocompletion unterstützt, muss in Eclipse Oxygen die neue module-info.java Datei noch händisch befüllt werden.

Wer die Muschel hat darf… Live-Hacken: Die JShell

Die JShell ist eine kleine Anwendung, die mit dem JDK9 ausgeliefert wird. Sie ist ein ziemlich vielseitiges kleines Werkzeug, das es ermöglicht, Java Code einfach und direkt auszuführen. Und dabei kann sie deutlich mehr als nur das typische „System.out.println(„Hello World“);“

Anfänger und Codehelden werden gleichermaßen ihren Spaß damit haben, direktes Feedback zu ihrem Code zu erhalten – ganz ohne lästige Boilerplate.

Was anfangs als Spaßbremse wirkt ist der langsame initiale Start. Danach ist die Konsole allerdings enorm flink.

Von einzelnen Statements bis hin zur Erstellung kleiner Klassen, Interfaces oder Enums ist hier dem Protoyping kaum eine Grenze gesetzt. Variablen und Methoden können deklariert und in späteren Statements wieder aufgegriffen werden, Klassen aus dem Java Standardumfang können ohne weiteres importiert werden und auch der Classpath kann erweitert werden. Wobei sich dann schon bald die Frage stellt, ob der gerade entstehende Prototyp in einer IDE mit entsprechendem Dependency Management nicht doch besser aufgehoben wäre.

it-economics_JShell_1.png

Um in all dem Hacking die Übersicht zu wahren kann man mit den nützlichen Kommandos /vars und /methods alle deklarierte Variablen bzw. Methoden nochmals sehen und mit /list den ganzen bisher geschriebenen Code nochmals anzeigen lassen.

Die JShell unterstützt neben diesen Kommandos auch mit einigen Shortcuts. Gewöhnungsbedürftig sind hier allenfalls Kleinigkeiten, z.B. dass die Shortcuts für den Import von Klassen <SHIFT + TAB>, <i> statt <SHIFT + TAB + i> ist. Das kennt man vom täglichen Umgang mit der IDE anders.

Zu guter Letzt lässt sich über /save der gebastelte Prototyp auch noch speichern und somit entweder zur weiteren Entwicklung in eine IDE übernehmen oder zu einem späteren Zeitpunkt wieder in die JShell laden.

it-economics_JShell_2.png

Stapellauf statt Spurensuche. Das StackWalk-API

Es gibt Situationen, da möchte man mehr über das Innenleben einer Anwendung zur Laufzeit wissen. Beispielsweise um den internen Programmablauf zu verstehen, um einem Resource Leak nachzugehen oder um zu prüfen, dass bestimmte Methoden nur von Code aufgerufen werden, der das auch darf.

Wenn man vor Java 9 etwas darüber wissen wollte, wer eigentlich wen aufruft gab es dafür auch schon Möglichkeiten. Man konnte sich mit Throwables behelfen, so den StackTrace erhalten und darüber die Aufrufhierarchie ermitteln. Das Ganze sah nicht nur relativ unsauber aus, es war auch ziemlich teuer. Da der komplette StackTrace als Array von StackTraceElementen bereitgestelllt wurde.

Das ändert sich nun. Mit StackWalker können StackTraceInformationen per lazy Access abgegriffen und komfortabel gefiltert werden. Über StackWalk.getInstance() kann man sich einen StackWalker liefern lassen, den man mit walk() durchläuft. Man erhält dann einen Stream von StackFrames und kann so z.B. alle die Frames herausfiltern, die aktuell nicht interessieren oder nur genauso viele Frames „durchlaufen“ wie man zur Untersuchung des aktuellen Problems benötigt. Das ist schnell, leichtgewichtig und sehr komfortabel.

Diverse Konfigurationsmöglichkeiten des StackWalk-APIs wie z.B. Anzeige von Hidden Frames und die deutlich bessere Performance verglichen mit dem Throwables-Ansatz machen die Nutzung gerade in großen Anwendungen interessant.

Java 8 weitergedacht

Neben diesen neuen, raumgreifenden Features ist Java 9 aber in vielerlei Hinsicht vor allem eine sinnvolle Erweiterung zu Java 8. Die in Java 8 weit geöffnete Tür zur Unterstützung der funktionalen Programmierung erhält in Java 9 nochmals einen Feinschliff.

So wurden Optionals um die drei Methoden or(), ifPresentOrElse() und stream() erweitert.

Während das mit Java 8 bereits eingeführte orElse() dazu führt, dass entweder der Wert aus dem Optional, oder (falls der Wert nicht existiert) den in orElse() angegebenen Wert zurückliefert, liefert or() entweder das eigentliche Optional, oder falls dieses leer ist ein das in or() angegebene Optional zurück. Man kann also direkt auf einem Optional weiterarbeiten.

Die neue Methode ifPresentOrElse() kann mit einem Consumer ein Objekt verarbeiten, sofern es vorhanden ist, oder eine vom Objekt unabhängige Aktion (mit einem Runnable) ausführen, sofern das Optional leer ist. Das ist beispielsweise praktisch, falls man auf den Fall, dass ein Optional leer ist speziell reagieren möchte. Zuvor hatte man in für die spezielle Behandlung dieser Fälle immer nach der eigentlichen Operation noch einen der lästigen „if(!optional.isPresent())“ Blöcke benötigt.

Ebenfalls hinzugekommen ist stream(). Hier wird aus einem Optional<T> ein Stream<T>. Sollte das Optional leer sein, so ist auch der resultierende Stream leer. Die stream() Methode hilft zum einen beim Anhängen von Werten eines Optionals an einen Stream mittels Stream.concat() zum anderen verhindert es, dass man Streams mit tief verschachtelten Optionals baut, nur um sich das Entpacken der Werte zu ersparen.

Apropos Streams. Das Äquivalent zu Optional.stream() ist Stream.ofNullable(). Und das ist nicht die einzige Neuerung. Es ist nun wesentlich einfacher Bedingungen über den Inhalt von Streams zu definieren. Mit takeWhile() werden Daten aus einem Stream so lange geliefert bis die Bedingung in takeWhile() erfüllt wurde. Das Gegenstück dazu ist „dropWhile()“ womit ein Stream nur solche Elemente liefert, die nicht zur dort angegebenen Bedingung passen. Mit iterate() dagegen können für einen Stream mit einem Startwert bis zum Eintritt einer Abbruchbedingung neue Werte generiert werden.

Die vier neuen Methoden sind als default- bzw. static-Methoden am Stream Interface realisiert. Damit sind Java 8 Streams dazu abwärtskompatibel. Und wo wir gerade bei Interfaces sind - auch hier gibt es Neuigkeiten:

So schön auch die neuen Möglichkeiten sind, die (vor allem) die default-Methoden in Interfaces mit sich bringen, so unangenehm konnte es mit Java 8 sein, solche Methoden zu erstellen. Denn man stand des Öfteren vor der Wahl, in mehreren default-Methoden benötigten Code entweder zu duplizieren oder in eine eigene default-Methode auszulagern. Das hatte aber den Nachteil, dass diese für jeden benutzbar waren. Java 9 greift hier ein und erlaubt nun auch private default- (und static-) Methoden. Diese sind nur innerhalb des Interfaces sichtbar. So kann mehrfach verwendeter Code nun in Methoden ausgelagert und trotzdem nur den anderen Methoden im Interface zugänglich gemacht werden.

Auch wenn die Liste der neuen Features in Java 9 noch ein ganzes Stück länger ist, gibt es bei der Vorstellung der Features mit Alltagstauglichkeit vor allem noch eines hervorzuheben: Die Factory-Methoden für Collections. Mit Set.of(), Map.of() und List.of() lassen sich nun wesentlich einfacher als zuvor Collections erzeugen.

Fazit

Java 9 kommt mit vielen neuen Features, die die Ideen der Vorgängerversionen abrunden. Trotzdem hat es nicht die Dimension von Java 8 und wird in dessen Schatten stehen. Denn mit der Einführung der funktionalen Programmierung in Java 8 und damit der Annäherung an die Paradigmen von Sprachen wir Scala hat sich für den Java-Entwickler eine ganz neue Welt geöffnet. Mit Werkzeugen, die das Entwicklerleben bei richtigem Einsatz enorm erleichtern, bei maßloser Nutzung aber auch verzweifeln lassen können. Nur wer die Konzepte von Java 8 versteht, dem hilft Java 9 auch weiter.

Sie möchten funktionale Programmierung mit Java lernen? Hier erfahren Sie mehr zu unserem Trainingsangebot: https://www.it-economics.de/java-8-schulung