Java 21 (LTS)
Java 21 (September 2023) ist eine LTS-Version. Zwischen Java 18 und 21 sind wichtige Sprach- und Plattform-Features gereift: von Vorschauen (Preview/Incubator) hin zu finalen Features. Diese Seite fasst die wichtigsten Highlights zusammen und zeigt kurze Beispiele.
- Virtual Threads (leichtgewichtige Threads) – Vorschau in 19/20, final in 21
- Pattern Matching für
switch– mehrere Vorschauen, final in 21 - Record Patterns – Vorschau 19/20, final in 21
- Sequenced Collections – neu in 21
- String Templates – Vorschau in 21, später zurückgezogen (nicht in JDK 23+)
- Foreign Function & Memory API – mehrere Vorschauen bis 21, final in 22
- Structured Concurrency – Vorschau in 21
- Generational ZGC – neu in 21
- Praktische Tools/Defaults: Simple Web Server (18), „UTF-8 by default“ (18)
Ein sehr einfacher, statischer Webserver für lokale Tests und Demos.
jwebserver --directory . --port 8000
Aufruf liefert statische Dateien aus dem aktuellen Verzeichnis aus.
Seit Java 18 ist UTF‑8 die Standard-Charset-Plattform. Das reduziert Encoding-Fallen über Plattformen hinweg.
Wesentliche Themen in 19 und 20 waren Vorschauen/Incubators, die in 21 finalisiert oder weitergeführt wurden:
- Virtual Threads (Project Loom) – Vorschau in 19/20
- Pattern Matching für
switch– weitere Vorschauen - Record Patterns – Vorschau (19) und zweite Vorschau (20)
- Foreign Function & Memory API – Vorschauen (19/20)
- Structured Concurrency – Incubator/Preview
- Vector API – fortgesetzter Incubator
Die folgenden Abschnitte zeigen die finalen Formen in Java 21.
Virtual Threads ermöglichen sehr viele nebenläufige Aufgaben mit minimalem Overhead – ideal für serverseitige I/O-lastige Workloads.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class VirtualThreadsDemo {
public static void main(String[] args) throws Exception {
try (ExecutorService es = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 1_000; i++) {
int id = i;
es.submit(() -> {
System.out.println("Task " + id + " auf " + Thread.currentThread());
// I/O-Operationen skalieren besonders gut
Thread.sleep(10);
return null;
});
}
}
}
}
Nutzen: kaum Blockierkosten pro Thread, einfache Migration von „klassischem“ Threading-Code.
switch kann jetzt auf Muster matchen und Variablen binden, inklusive Guard-Clauses (when).
class SwitchPatternDemo {
static String describe(Object o) {
return switch (o) {
case Integer i when i > 0 -> "Positive Zahl: " + i;
case Integer i -> "Nicht-positive Zahl: " + i;
case String s when s.isBlank() -> "Leerer String";
case String s -> "String (Länge=" + s.length() + ")";
case null -> "null";
default -> "Sonstiges: " + o.getClass().getSimpleName();
};
}
}
Nutzen: weniger instanceof/Casting, kompaktere Fallunterscheidungen.
Record-Objekte lassen sich direkt per Muster zerlegen. Verschachtelte Muster werden unterstützt.
record Point(int x, int y) {}
class RecordPatternDemo {
static int manhattan(Object o) {
return switch (o) {
case Point(int x, int y) -> Math.abs(x) + Math.abs(y);
default -> 0;
};
}
}
Nutzen: sehr prägnante, ausdrucksstarke Destrukturierung in Kontrollfluss.
Neue Interfaces wie SequencedCollection, SequencedSet und SequencedMap bieten definierte Reihenfolge-Operationen (getFirst, getLast, reversed …).
import java.util.*;
class SequencedDemo {
public static void main(String[] args) {
SequencedCollection<String> sc = new ArrayDeque<>();
sc.addFirst("A");
sc.addLast("B");
System.out.println(sc.getFirst()); // A
System.out.println(sc.getLast()); // B
System.out.println(sc.reversed()); // Ansicht in umgekehrter Reihenfolge
}
}
Nutzen: einheitliche API für Datenstrukturen mit Reihenfolge.
In Java 21 und 22 gab es String Templates als Preview (STR."x = \{x}"). Vor JDK 23 wurde das Feature zurückgezogen. Es ist kein Weg zur Finalisierung und in aktuellen JDKs nicht mehr enthalten. Wer Interpolation braucht, bleibt bei Konkatenation, formatted() oder String.format.
Die FFM-API ermöglicht Typsichere Interop mit „native“ Code (C-Bibliotheken) ohne JNI-Boilerplate sowie sichere Off-Heap-Speicherverwaltung.
Mini‑Beispiel (konzeptionell; reale Nutzung erfordert passende nativen Symbole):
// Preview-API; Kompilierung mit --enable-preview nötig
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
class FFMDemo {
public static void main(String[] args) {
try (Arena arena = Arena.ofConfined()) {
MemorySegment seg = arena.allocate(4); // 4 Bytes Off-Heap
seg.setAtIndex(java.lang.foreign.ValueLayout.JAVA_INT, 0, 42);
int v = seg.getAtIndex(java.lang.foreign.ValueLayout.JAVA_INT, 0);
System.out.println(v); // 42
}
}
}
Nutzen: weniger JNI, klarere Speicherlebenszyklen, bessere Performance.
Vereinfacht die Koordination mehrerer Aufgaben, indem sie als Einheit behandelt werden.
// Preview-API
import java.util.concurrent.Callable;
import java.util.concurrent.StructuredTaskScope;
class StructuredConcurrencyDemo {
String fetch() throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Callable<String> a = () -> expensiveCall("A");
Callable<String> b = () -> expensiveCall("B");
var fa = scope.fork(a);
var fb = scope.fork(b);
scope.join();
scope.throwIfFailed();
return fa.resultNow() + "," + fb.resultNow();
}
}
static String expensiveCall(String id) throws InterruptedException {
Thread.sleep(50);
return id;
}
}
Nutzen: robuster paralleler Code mit klaren Abbruch- und Fehlersemantiken.
ZGC erhält eine Generationen-Variante, die kurzlebige von langlebigen Objekten trennt und so Durchsatz und Pausenzeiten weiter verbessert.
Aktivierung über JVM-Flags, z. B.:
java -XX:+UseZGC -XX:+ZGenerational ...
Mit Java 21 als LTS sind zentrale Themen wie Pattern Matching und Virtual Threads produktionsreif. Viele zuvor als Vorschau eingeführte Features sind konsolidiert; neue APIs (Sequenced Collections) und GC-Verbesserungen runden das Release ab. Projekte, die noch auf 17 LTS stehen, profitieren bei einem Upgrade vor allem von besserer Skalierbarkeit (Virtual Threads) und prägnanterem Code (Pattern- und Record-Patterns). Die aktuelle LTS ist Java 25.