Suche
Für das Plus an APIs

JEP 102 & JEP 269: API-Erweiterungen für Java 9

Michael Inden

© Shutterstock.com / Profit_Image

Das kürzlich erschienene Java 9 besteht aus mehr als nur Modulen und dem Projekt Jigsaw. Über 90 sogenannte JEPs (JDK Enhancement Proposals) sind Teil von Version 9 des Java Development Kits. Im zweiten Teil seiner Serie zu Java 9 stellt Michael Inden, Oracle-zertifizierter Java-Entwickler, einige mit JDK 9 eingeführte API-Erweiterungen vor.

Die vorliegende Artikelserie zu Java 9 setzt sich aus Texten von Michael Indens Buch „Java 9 – Die Neuerungen“ zusammen, das beim dpunkt.verlag erschienen ist.

PS: Verpassen Sie nicht unsere Infografik zu Project Jigsaw!

Nachdem wir im ersten Teil dieser Blog-Serie diverse kleinere Änderungen in der Syntax der Sprache Java kennengelernt haben, wollen wir uns nun einige relevante Erweiterungen im JDK anschauen. Erwähnenswert sind das Process-API und die Collection-Factory-Methoden, aber auch die Ergänzungen im Stream-API sowie in den Klassen java.util.Optional<T> und java.time.LocalDate.

Das neue Process-API (JEP 102)

Bis einschließlich JDK 8 sind die Möglichkeiten recht eingeschränkt, wenn es darum geht, Prozesse des Betriebssystems zu kontrollieren und zu verwalten. Ein simples Beispiel ist die Ermittlung der ID eines Prozesses, kurz PID genannt. Je nach Plattform muss man dies mit Java 8 unterschiedlich implementieren und verschiedene Details beachten.

PID mit JDK 9 ermitteln

Die Abfrage der PID mit Java 9 wird mithilfe der Klasse java.lang.ProcessHandle nun deutlich kürzer, besser lesbar und verständlich:

private static long getPidJdk9Style() throws InterruptedException, IOException
{
    return ProcessHandle.current().pid();
}

Neben den genannten Vorteilen bietet die Methode pid() einen betriebssystemunabhängigen Weg zur Ermittlung der Prozess-ID (zumindest aus Sicht des Aufrufers).

Das Interface ProcessHandle

Neben der PID kann man mithilfe von ProcessHandle noch diverse weitere Informationen zu Prozessen auslesen. Dazu gibt es unter anderem folgende Methoden:

  • current() – Ermittelt den aktuellen Prozess als ProcessHandle.
  • info() – Stellt Infos zum Prozess in Form des inneren Interface ProcessHandle.Info bereit, etwa zu Benutzer, Kommando usw.
  • info().command() – Gibt das Kommando als Optional<String> aus einem ProcessHandle.Info zurück.
  • info().user() – Liefert den Benutzer als Optional<String>; aus einem ProcessHandle.Info.
  • info().totalCpuDuration() – Ermittelt aus den Infos die benötigte CPU-Zeit als Optional<Duration>. Die Klasse java.time.Duration entstammt dem mit JDK 8 neu eingeführten Date and Time API.

Alle Prozesse mit ProcessHandle abfragen

Neben Informationen zum aktuellen Prozess lassen sich Informationen für alle Prozesse des Benutzers sowie alle Subprozesse zu einem Prozess wie folgt ermitteln:

  • allProcesses() – Liefert alle Prozesse als Stream<ProcessHandle>.
  • children() – Ermittelt zu einem Prozess alle seine (direkten) Subprozesse als
    Stream<ProcessHandle>.

Zum besseren Verständnis der vorgestellten Methoden betrachten wir ein Beispiel:

public static void main(final String[] args) throws InterruptedException, IOException
{
    System.out.println("All Processes:");
    showInfoForAllProcesses();
}

private static void showInfoForAllProcesses()
{
    ProcessHandle.allProcesses().forEach(processHandle ->
    {
        final Stream<ProcessHandle> children = processHandle.children();
        final long count = children.count();
        if (count > 0)
        {
            System.out.println("Info: " + processHandle.info() + " has " + count + " children");

            System.out.println("Command: " + processHandle.info().command());
            System.out.println("CPU-Usage: " + processHandle.info().totalCpuDuration());
        }
    });
}

Lesen Sie auch: Java 9 ist da! Project Jigsaw & die neuen Features auf einen Blick

Collection-Factory-Methoden (JEP 269)

Das Erzeugen von Collections für einige vordefinierte Werte ist in Java mitunter etwas umständlich. Sprachen wie Groovy oder Python bieten dafür eine spezielle Syntax, sogenannte Collection-Literale. Bereits 2009 hat man auch für Java über Derartiges nachgedacht. Leider wurde dies nicht realisiert, obwohl es einige vielversprechende Vorschläge gab.

Nachfolgendes Listing zeigt, wie eine mögliche Syntax für Collection-Literale für die im Package java.util definierten Collections List<E>, Set<E> und Map<K,V> aussehen könnte. Dabei werden die Elemente der Collection in geschweifte oder eckige Klammern eingeschlossen:

// Leider weder mit JDK 8 noch JDK 9 umgesetzt
final List<String> newStyleList = ["item1", "item2"];
final Set<String> newStyleSet = {"Tim", "Mike"};
final Map<String, String> newStyleMap = ["key1" : "value1", "key2" : "value2"];

Realisierung mit JDK 9

Leider wurden Collection-Literale nicht in der zuvor beschriebenen Form in Java 9 realisiert. Stattdessen wurde eine Armada von Factory-Methoden mit den Namen of() bzw. ofEntries() in die Interfaces List<E>, Set<E> und Map<K,V> integriert, die sich wie folgt zur Erzeugung von Collections nutzen lassen (zur besseren Lesbarkeit erfolgt ein statischer Import von java.util.Map.entry):

public static void main(final String[] args)
{
    final List<String> names = List.of("MAX", "MORITZ", "MIKE");
    names.forEach(name -> System.out.println(name));
    
    final Set<Integer> numbers = Set.of(1, 2, 3);
    numbers.forEach(number -> System.out.println(number));

    final Map<Integer, String> mapping = Map.of(5, "five", 6, "six");
    final Map<Integer, String> mapping2 = Map.ofEntries(entry(5, "five"), entry(6, "six"));

    mapping.forEach((key, value) -> System.out.println(key + ":" + value));
    mapping2.forEach((key, value) -> System.out.println(key + ":" + value));
}

Startet man das obige Programm, so kommt es zu folgenden Ausgaben:

MAX
MORITZ
MIKE
1
2
3
6:six
5:five
6:six
5:five

Beim Einsatz der Collection-Factory-Methoden sollte man ein Detail für Set<E> und Map<K,V> kennen: Bekanntermaßen modelliert ein Set<E> das mathematische Konzept einer Menge und enthält somit keine Duplikate. Das gilt auch für die Schlüssel in Maps. Diese Eigenschaft wurde bei den bisherigen Collections automatisch sichergestellt, indem beim Einfügen von Elementen gegebenenfalls Duplikate aussortiert wurden (was erfordert, dass die steuernden Methoden wie equals(), hashCode() usw. korrekt implementiert sind).

Das war für diverse Anwendungsfälle ein recht praktisches Feature. Die Collection-Factory-Methoden weisen allerdings eine nicht überraschungsfreie Besonderheit auf: Für Sets wird zum Konstruktionszeitpunkt die Duplikatfreiheit geprüft. Ist diese nicht gegeben, so wird eine Exception ausgelöst. Gleiches gilt auch für Duplikate bei den Schlüsseln von Maps. Bei Listen findet dagegen – wie erwartet – keine Duplikatsprüfung statt. Schauen wir uns ein Beispiel an:

final Set<String> names = Set.of("MAX", "Moritz", "MAX");

Bei dieser Variablendefinition kommt es zur Laufzeit zu folgender Exception:

java.lang.IllegalArgumentException: duplicate element: MAX
    at java.base/java.util.ImmutableCollections$SSetN.<init>(ImmutableCollections
        .java:462)

Weil die Collections direkt anhand der übergebenen Werte konstruiert werden, kann man jedoch auch einen Grund für dieses Verhalten finden, nämlich die Vermeidung von Inkonsistenzen durch Flüchtigkeitsfehler in Form einer Mehrfachangabe von Werten.

Java 9 – Die Neuerungen

Michael Indens Buch bietet einen fundierten Einstieg in Java 9 sowie einen Überblick über die umfangreichen Neuerungen in der aktuellen Version. Damit eignet sich das Buch für all jene, die ihr Java-Wissen aktualisieren wollen. Dabei helfen eine Vielzahl an Übungen, um die einzelnen Themengebiete zu vertiefen und besser zu verstehen.

Neben Änderungen an der Sprache bilden auch die Erweiterungen in diversen APIs einen Schwerpunkt. Fehlen darf hier natürlich auch nicht ein Kapitel über die fundamentalste Änderung in Java 9: Project Jigsaw. Auch fortgeschrittenere Themen wie Services und die Migration bestehender Applikationen werden besprochen. Da Java 9 auch einige Auswirkungen auf Build Tools und IDEs mit sich bringt, gibt ein Kapitel einen Überblick über den derzeitigen Stand zum Tooling rund um die neue Java-Version.

Weitere Informationenen zum Buch gibt es hier!

Verwandte Themen:

Geschrieben von
Michael Inden
Michael Inden
Dipl.-Inform. Michael Inden ist Oracle-zertifizierter Java-Entwickler für JDK 6. Nach seinem Studium in Oldenburg war er lange Zeit als Softwareentwickler und -architekt bei verschiedenen internationalen Firmen tätig und arbeitet derzeit als Teamleiter Softwareentwicklung in Zürich. Michael Inden hat rund 20 Jahre Erfahrung beim Entwurf komplexer Softwaresysteme gesammelt, an diversen Fortbildungen und an mehreren Java-One-Konferenzen in San Francisco teilgenommen. Sein Wissen gibt er gerne als Trainer in Schulungen und auf Konferenzen weiter. Sein besonderes Interesse gilt dem Design qualitativ hochwertiger Applikationen mit ergonomischen, grafischen Oberflächen sowie dem Coaching von Kollegen.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.