11 Gründe

Darum bleibt Java relevant

19.01.2024
Von 
Peter Wayner schreibt unter anderem für unsere US-Schwesterpublikation InfoWorld.com und ist Autor verschiedener Bücher - unter anderem zu den Themen Open Source Software, autonomes Fahren und digitale Transaktionen.
Java ist seiner ursprünglichen Vision längst entwachsen. Mit Blick auf die Zukunftsfähigkeit der Programmiersprache ist das eine gute Sache.
"Java - bist Du´s?"
"Java - bist Du´s?"
Foto: Stefan Csontos | shutterstock.com

Am 23. Mai 1995 erblickte Java offiziell das Licht der Welt - und entwickelte sich in der Folge zu einer essenziellen Grundlage für moderne Software, die nahezu überall zum Einsatz kommt. Trotz ihres Alters kann man jedoch nicht davon sprechen, dass Java zum alten Eisen gehört. Das liegt auch daran, dass Sun Microsystems und (ab 2010) Oracle bemerkenswerte Arbeit geleistet haben, um die Programmiersprache kontinuierlich mit neuen Funktionen auszustatten - ohne dabei die Kernfunktionen zu stark zu verändern.

Das hat allerdings auch dazu geführt, dass sich Java seit seinen Anfangszeiten dramatisch verändert hat - im Wesentlichen zum Besseren. Im Folgenden haben wir elf Gründe zusammengetragen, die dafür sprechen, dass Java auch in Zukunft relevant bleibt.

1. Virtual Threads

Die ursprüngliche Java-Version ermöglichte Entwicklern, ihre eigenen Thread-Objekte zu erstellen und zu steuern, wie der Code in Multithread- und Multicore-Umgebungen ausgeführt wird. Dabei stellten die Developer schnell fest, dass die Thread-Objekte ziemlich groß waren und es viel Zeit kostete, sie zu erstellen und wieder aufzulösen. Einen permanenten Thread-Pool zum Programmstart einzurichten, wurde so zu einem gängigen Workaround.

Mit Java 19 und der Einführung von Virtual Threads war all das passé: Seitdem übernimmt die Java Virtual Machine (JVM) das Gros der Arbeit, wenn es darum geht, die Systemressourcen in Java-Programmen zu verteilen. Dazu geben die Programmierer einfach an, wenn Parallelität verfügbar ist - die JVM führt den Code zur Laufzeit aus, wo immer sie kann. Insbesondere für moderne IT-Architekturen wie Microservices sind virtuelle Threads ein Segen, weil sie einfacher zu entwickeln und zu supporten sind.

2. Structured Concurrency

Doch damit nicht genug: Java verfügt inzwischen auch über ein abstraktes Modell für Parallelität, das Programmierern und JVM das Leben leichter macht, wenn es darum geht, Workloads zeitgleich zu verarbeiten. Das neue Structured-Concurrency-Modell ermöglicht Devs, einen Java Workload in verschiedene Tasks zu unterteilen, die wiederum in sogenannten Scopes gruppiert werden. Die Scopes werden in Fibers zusammengefasst, die im selben Thread zusammenarbeiten.

Das Ziel dabei: Java-Entwicklern eine Blaupause an die Hand zu geben, um parallele Programme zu erstellen. Structured Concurrency erleichtert zudem der JVM, Möglichkeiten für eine gleichzeitige Execution zu identifizieren und diese den Prozessorkernen zuzuordnen.

3. Immutable Data

In der Anfangszeit von Java waren Strings in Stein gemeißelt: Sobald sie erstellt waren, konnten sie nicht mehr verändert werden. Eine Funktion wie toLowerCase aufzurufen, erzeugte einen neuen String. Dieser Prozess erleichterte es der JVM, die Synchronisation über Threads hinweg sicherzustellen und abzusichern.

Heute können Java-Entwickler die gleichen Regeln der Unveränderbarkeit für ihre eigenen Objekte festlegen - mit "Records". Der Code listet die Namen und Typen der Felder auf und die JVM erledigt den Rest. Gängige Methoden wie equals, hashCode und toString werden dabei automatisch erstellt. Unterdessen sorgt die JVM für die Unveränderlichkeit der Records. Das vereinfacht viele Programmdetails und beschleunigt den laufenden Code.

4. Garbage Collection

Speicherzuweisung und -rückgewinnung an die JVM zu delegieren, kommt den meisten Entwicklern gelegen. Dabei wirkte sich der ursprüngliche Garbage Collector (GC) von Java jedoch in manchen Fällen spürbar auf die Performance respektive User Experience aus. Inzwischen stehen Java-Programmierer vier verschiedene Garbage Collectors zur Auswahl, die unterschiedliche Algorithmen nutzen und auf spezifische Applikationen ausgelegt sind:

  • Der Garbage First (G1) Garbage Collector ist die Default-Option, die einen optimierten Durchsatz mit kürzeren Pausen bietet. G1 baut auf Techniken auf, die aus früheren Iterationen der Java-Garbage-Collection entstanden sind.

  • Der Z Garbage Collector ist auf sehr geringe Latenzzeiten ausgelegt - eine Voraussetzung für Webserver, Streaming-Dienste und andere Echtzeit-Szenarien. Weil er auf bis zu 16 TB RAM skaliert werden kann, kommt er auch mit einem sehr großen Heap zurecht.

  • Der Concurrent Garbage Collector hält sich vollständig im Hintergrund, die Anwendung muss nicht unterbrochen werden. Dieser GC ist weniger effizient, ist jedoch ideal für interaktive Applikationen geeignet, die ununterbrochen laufen sollen.

  • Der Parallel Collector nutzt mehrere Threads, um Daten schneller einzusammeln. Dafür sind die Unterbrechungen unberechenbar.

Das macht es für Entwickler überflüssig, auf andere Lösungen zurückzugreifen - etwa das eigene Memory Management zu simulieren, indem Objekte wiederverwendet werden. Jede der vier GC-Optionen bietet zudem weitere Möglichkeiten zum Feintuning und für Experimente.