{"id":56104,"date":"2026-06-04T00:01:19","date_gmt":"2026-06-03T22:01:19","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=56104"},"modified":"2026-06-04T00:01:22","modified_gmt":"2026-06-03T22:01:22","slug":"java-27-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-27-features\/","title":{"rendered":"Java 27 Features (mit Beispielen)"},"content":{"rendered":"\n<p>Java 27 befindet sich seit dem 4. Juni 2026 in der sogenannten \u201eRampdown Phase One\u201c, d. h. es werden keine weiteren JDK Enhancement Proposals (JEPs) in das Release aufgenommen. Das Feature-Set steht also fest. Es werden nur noch Bugs gefixt und ggf. kleinere Verbesserungen durchgef\u00fchrt.<\/p>\n\n\n\n<p>Als Ver\u00f6ffentlichungsdatum ist der 14. September 2026 angepeilt. Die aktuelle Early-Access-Version kannst du <a href=\"https:\/\/jdk.java.net\/27\/\" target=\"_blank\" rel=\"noopener\">hier<\/a> herunterladen.<\/p>\n\n\n\n<p>Java 27 ist \u2013 wie schon <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/\">Java 26<\/a> \u2013 ein sehr \u00fcberschaubares Release: Es enth\u00e4lt lediglich neun JEPs. Mehr als die H\u00e4lfte davon sind wiedervorgelegte Preview- und Incubator-Features: drei mit kleinen \u00c4nderungen (<a href=\"#lazy-constants-third-preview-jep-531\">Lazy Constants<\/a>, <a href=\"#structured-concurrency-seventh-preview-jep-533\">Structured Concurrency<\/a> und <a href=\"#pem-encodings-of-cryptographic-objects-jep-538\">PEM Encodings<\/a>) und zwei ganz ohne \u00c4nderungen (<a href=\"#primitive-types-in-patterns-instanceof-and-switch-fifth-preview-jep-532\">Primitive Type Patterns<\/a> und die <a href=\"#vector-api-twelfth-incubator-jep-537\">Vector API<\/a>).<\/p>\n\n\n\n<p>Vier Features sind neu: Compact Object Headers sind <a href=\"#compact-object-headers-by-default-jep-534\">ab Java 27 standardm\u00e4\u00dfig aktiviert<\/a>; G1 ist auch auf kleinen Instanzen der <a href=\"#make-g1-the-default-garbage-collector-in-all-environments-jep-523\">Default Garbage Collector<\/a>; TLS unterst\u00fctzt jetzt <a href=\"#post-quantum-hybrid-key-exchange-for-tls-1-3-jep-527\">quantensichere Verschl\u00fcsselung<\/a>, und der Java Flight Recorder kann <a href=\"#jfr-in-process-data-redaction-jep-536\">vertrauliche Informationen in Umgebungsvariablen, System Properties und Programmargumenten schw\u00e4rzen<\/a>.<\/p>\n\n\n\n<p>F\u00fcr alle JEPs und \u00c4nderungen aus den Release Notes verwende ich wie immer die originalen, englischen Bezeichnungen.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"compact-object-headers-by-default-jep-534\">Compact Object Headers by Default \u2013 JEP 534<\/h2>\n\n\n\n<p>Compact Object Headers (von 96 auf 64 Bit komprimierte Objekt-Header) wurden in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#compact-object-headers-experimental-jep-450\">Java 24<\/a> als experimentelles Feature eingef\u00fchrt. In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-25-features\/#compact-object-headers-jep-519\">Java 25<\/a> wurden sie zu einem produktiven Feature, mussten aber noch explizit mit <code>-XX:+UseCompactObjectHeaders<\/code> aktiviert werden.<\/p>\n\n\n\n<p>In Java 27 werden sie durch <a href=\"https:\/\/openjdk.org\/jeps\/534\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 534<\/a> standardm\u00e4\u00dfig aktiviert. Sie k\u00f6nnen aktuell noch mit <code>-XX:-UseCompactObjectHeaders<\/code> deaktiviert werden \u2013 diese Option wird aber in einer zuk\u00fcnftigen Java-Version entfernt werden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"herkoemmliche-objekt-header-96-bit-12-byte\">Herk\u00f6mmliche Objekt-Header: 96 Bit \/ 12 Byte<\/h3>\n\n\n\n<p>Jedes Java-Objekt besteht im Speicher aus zwei Teilen: dem Objekt-Header und den eigentlichen Nutzdaten. Der Objekt-Header war bisher in zwei Teile aufgeteilt: das <em>Mark Word<\/em> (auch als <em>Lock Word<\/em> bezeichnet) und das <em>Class Word<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"217\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-800x217.png\" alt=\"Java Object Header: Mark Word und Class Word\" class=\"wp-image-41735\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-800x217.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-224x61.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-336x91.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-504x137.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-672x182.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-400x109.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-600x163.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-944x256.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3-1200x326.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-java-object-header-mark-word-class-word.v3.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Der herk\u00f6mmliche Objekt-Header bestehend aus Mark Word und Class Word<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Das Mark Word enthielt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>den Identity Hash Code (der von <code>System.identityHashCode()<\/code> zur\u00fcckgegebene Wert), <\/li>\n\n\n\n<li>das Objekt-Alter (vom Garbage Collector verwendet, um zu entscheiden, wann ein Objekt von der Young Generation in die Old Generation verschoben wird),<\/li>\n\n\n\n<li>zwei Lock-Bits, die u. a. f\u00fcr das <code>synchronized<\/code>-Locking verwendet werden,<\/li>\n\n\n\n<li>insgesamt 27 ungenutzte Bits (25 am Anfang und je eines vor und nach den vier Age-Bits).<\/li>\n<\/ul>\n\n\n\n<p>Das Class Word enthielt einen 32-Bit-Offset zu den Klassen-Metadaten im sogenannten Compressed Class Space. Durch das Class Word wei\u00df die JVM von welcher Klasse ein Objekt ist.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"compact-object-headers-64-bit-8-byte\">Compact Object Headers: 64 Bit \/ 8 Byte<\/h3>\n\n\n\n<p>Im neuen kompakten Objekt-Header sind Mark Word und Class Word zu einem einzigen 64-Bit-Wert verschmolzen. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"174\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-800x174.png\" alt=\"Aufbau Compact Object Header in Java 25\" class=\"wp-image-41736\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-800x174.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-224x49.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-336x73.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-504x110.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-672x146.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-400x87.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-600x131.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-944x205.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2-1200x261.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/11\/jep-450-compact-object-header-java.v2.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Der neue kompakte 64-Bit-Objekt-Header<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Dieser enth\u00e4lt unver\u00e4ndert:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>31 Bit f\u00fcr den Identity Hash Code,<\/li>\n\n\n\n<li>4 Bit f\u00fcr das Objekt-Alter,<\/li>\n\n\n\n<li>und die zwei Lock-Bits.<\/li>\n<\/ul>\n\n\n\n<p>Die 27 zuvor ungenutzten Bits werden im kompakten Header wie folgt belegt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>22 Bit durch einen komprimierten Class Pointer (dadurch f\u00e4llt das Class Word weg; wie genau der Class Pointer von 32 Bit auf 22 Bit gek\u00fcrzt werden konnte, kannst du im <a href=\"https:\/\/www.happycoders.eu\/de\/java\/compact-object-headers\/\">Hauptartikel \u00fcber Compact Object Headers<\/a> nachlesen),<\/li>\n\n\n\n<li>1 Bit f\u00fcr das neue Self-Forwarded-Bit (auch dar\u00fcber erf\u00e4hrst du mehr im zuvor genannten Hauptartikel)<\/li>\n\n\n\n<li>4 Bit werden f\u00fcr Project Valhalla (Value Classes) reserviert.<\/li>\n<\/ul>\n\n\n\n<p>Durch die standardm\u00e4\u00dfige Aktivierung von Compact Object Headers wird der Heap-Verbrauch bei einem Upgrade auf Java 27 \u2013 insbesondere bei Anwendungen mit vielen kleinen Objekten \u2013 um ca. 10\u201320 % reduziert und der Durchsatz um ca. 5\u201310 % erh\u00f6ht.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"jfr-in-process-data-redaction-jep-536\">JFR In-Process Data Redaction \u2013 JEP 536<\/h2>\n\n\n\n<p>Wird eine Java-Anwendung mit aktiviertem <a href=\"https:\/\/dev.java\/learn\/jvm\/jfr\/\" target=\"_blank\" rel=\"noopener\">JDK Flight Recorder<\/a> gestartet (dem in die JVM integrierten Monitoring- und Profiling-Tool), zeichnet dieser u. a. die Umgebungsvariablen, die System Properties und die Programm-Argumente mit auf.<\/p>\n\n\n\n<p>Oft werden jedoch vertrauliche Informationen \u2013 wie Access Tokens f\u00fcr APIs oder Passw\u00f6rter f\u00fcr Datenbanken oder Keystores \u2013 \u00fcber Umgebungsvariablen, System Properties oder Programm-Argumente an die Anwendung \u00fcbergeben, wie in folgendem Beispiel:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">$ <span class=\"hljs-built_in\">export<\/span> ACCESS_TOKEN=SECRET_ACCESS_TOKEN\n$ java -XX:StartFlightRecording:filename=recording.jfr \\\n       -Djavax.net.ssl.keyStorePassword=SECRET_KEYSTORE_PASSWORD \\\n       -jar application.jar \\\n       --dbpassword SECRET_DATABASE_PASSWORD<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Ein Angreifer mit Zugriff auf die Flight-Recorder-Aufzeichnung k\u00f6nnte Token und Passw\u00f6rter problemlos aus der Aufzeichnung extrahieren.<\/p>\n\n\n\n<p>Um das zu verhindern, wird ab Java 27 alles, was wahrscheinlich ein Token oder ein Passwort ist, automatisch in der JFR-Aufzeichnung geschw\u00e4rzt (englisch: <em>redacted<\/em>) und erscheint als <code>[REDACTED]<\/code>.<\/p>\n\n\n\n<p>Woher wei\u00df der Flight Recorder, was ein Token oder ein Passwort ist?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"standardkonfiguration\">Standardkonfiguration<\/h3>\n\n\n\n<p>Standardm\u00e4\u00dfig schw\u00e4rzt der Flight Recorder alle Umgebungsvariablen oder System Properties mit einem Key, der auf eines der folgenden Pattern matcht (Gro\u00df-\/Kleinschreibung wird dabei ignoriert, und das Sternchen ist ein Platzhalter f\u00fcr beliebige andere Zeichen):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">*api*key*\n*auth*\n*client*secret*\n*credential*\n*jaas*config*\n*jwt*\n*passphrase*\n*passwd*\n*password*\n*private*key*\n*pwd*\n*secret*\n*token*<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Zudem werden alle Programm-Argumente (oder Paare von Programm-Argumenten) geschw\u00e4rzt, die auf eines der folgenden Pattern matchen (ein Leerzeichen steht dabei f\u00fcr das Leerzeichen zwischen zwei aufeinanderfolgenden Argumenten):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">-*api*key *\n-*client*secret *\n-*credential *\n-*jaas*config *\n-*jwt *\n-*passphrase *\n-*passwd *\n-*password *\n-*private*key *\n-*pwd *\n-*secret *\n-*token *\n*api*key*\n*client*secret*\n*credential*\n*jaas*config*\n*passphrase*\n*passwd*\n*password*\n*private*key*\n*pwd*\n*secret*\n*token*<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Im Beispiel zu Beginn des Abschnitts wurden die folgenden sensitiven Informationen beim Programmstart angegeben: <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>eine Umgebungsvariable mit dem Key <code>ACCESS_TOKEN<\/code> \u2013 diese matcht auf <code>*token*<\/code> und wird daher ab Java 27 geschw\u00e4rzt,<\/li>\n\n\n\n<li>die System Property <code>javax.net.ssl.keyStorePassword<\/code> \u2013 diese matcht auf <code>*password*<\/code> und wird daher geschw\u00e4rzt <\/li>\n\n\n\n<li>und das Programm-Argument-Paar <code>--dbpassword SECRET_DATABASE_PASSWORD<\/code> \u2013 dieses matcht auf <code>-*password *<\/code> und wird daher ebenfalls geschw\u00e4rzt.<\/li>\n<\/ul>\n\n\n\n<p>Diese Pattern matchen bewusst gro\u00dfz\u00fcgig \u2013 im Zweifel wird lieber zu viel als zu wenig geschw\u00e4rzt. Das kann auch harmlose Werte treffen: Eine Umgebungsvariable namens <code>TOKEN_REFRESH_INTERVAL<\/code> etwa enth\u00e4lt kein Geheimnis, matcht aber auf <code>*token*<\/code> und erscheint dementsprechend als <code>[REDACTED]<\/code>. Falls dich die Schw\u00e4rzung eines konkreten, unkritischen Werts st\u00f6rt, kannst du die beiden Listen \u00fcber die im Folgenden gezeigten Parameter <code>redact-key<\/code> und <code>redact-argument<\/code> gezielt einschr\u00e4nken.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"aenderung-der-standardkonfiguration\">\u00c4nderung der Standardkonfiguration<\/h3>\n\n\n\n<p>Die Konfiguration, was geschw\u00e4rzt werden soll, kann auch ge\u00e4ndert werden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mit dem JFR-Parameter <code>redact-key<\/code> k\u00f6nnen wir die erste der zwei oben gezeigten Listen (die Pattern f\u00fcr Environment Variablen und System Properties) \u00fcberschreiben oder erweitern.<\/li>\n\n\n\n<li>Mit dem JFR-Parameter <code>redact-argument<\/code> k\u00f6nnen wir die zweite der oben gezeigten Listen (die Pattern f\u00fcr Programm-Argumente) \u00fcberschreiben oder erweitern.<\/li>\n<\/ul>\n\n\n\n<p>Wenn wir beispielsweise <em>nur<\/em> den Key <code>ACCESS_TOKEN<\/code> und die System Property <code>javax.net.ssl.keyStorePassword<\/code> schw\u00e4rzen wollten, k\u00f6nnten wir den Flight Recorder wie folgt starten:<\/p>\n\n\n\n<p><code>java -XX:FlightRecorderOptions:'redact-key=ACCESS_TOKEN;*keyStorePassword' ...<\/code><\/p>\n\n\n\n<p>Alternativ k\u00f6nnten wir eine Text-Datei erstellen, die die zwei Keys in je einer Zeile enth\u00e4lt. Hie\u00dfe diese Datei beispielsweise <code>keys.txt<\/code>, dann k\u00f6nnten wir auch den Namen dieser Datei \u2013 mit einem <code>@<\/code> voran \u2013 angeben:<\/p>\n\n\n\n<p><code>java -XX:FlightRecorderOptions:'redact-key=@keys.txt' ...<\/code><\/p>\n\n\n\n<p>Wenn wir die Standard-Schw\u00e4rzungslisten nicht <em>ersetzen<\/em>, sondern <em>erweitern<\/em> wollen, k\u00f6nnen wir der Liste von Keys (oder dem Dateinamen) ein <code>+<\/code> voranstellen, z. B. so:<\/p>\n\n\n\n<p><code>java -XX:FlightRecorderOptions:'redact-key=+*confidential*' ...<\/code><\/p>\n\n\n\n<p>In diesem Fall w\u00fcrden alle Environment Variablen oder System Properties geschw\u00e4rzt werden, die entweder auf ein Pattern aus der Standardliste matchen oder die den Begriff \u201econfidential\u201c enthalten.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"schwaerzen-ausschalten\">Schw\u00e4rzen ausschalten<\/h3>\n\n\n\n<p>Um das vorherige Verhalten wiederherzustellen, k\u00f6nnen wir das Schw\u00e4rzen durch Angabe von \u201enone\u201c vollst\u00e4ndig deaktivieren:<\/p>\n\n\n\n<p><code>java -XX:FlightRecorderOptions:'redact-key=none,redact-argument:none' ...<\/code><\/p>\n\n\n\n<p>Damit werden Umgebungsvariablen, System Properties und Programm-Argumente wieder uneingeschr\u00e4nkt aufgezeichnet.<\/p>\n\n\n\n<p>Die JFR In-Process Data Redaction ist in <a href=\"https:\/\/openjdk.org\/jeps\/536\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 536<\/a> spezifiziert.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"post-quantum-hybrid-key-exchange-for-tls-1-3-jep-527\">Post-Quantum Hybrid Key Exchange for TLS 1.3 \u2013 JEP 527<\/h2>\n\n\n\n<p>In Java 24 wurden Algorithmen zur <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#quantum-resistant-module-lattice-based-key-encapsulation-mechanism-jep-496\">quantensicheren Schl\u00fcsselkapselung (Key Encapsulation)<\/a> und f\u00fcr <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#quantum-resistant-module-lattice-based-digital-signature-algorithm-jep-497\">quantensichere digitale Signaturen<\/a> eingef\u00fchrt.<\/p>\n\n\n\n<p>Warum schon jetzt? Es gibt zwar aktuell noch keine Quantencomputer, die heutige Verschl\u00fcsselungsverfahren brechen k\u00f6nnen \u2013 aber ein Angreifer k\u00f6nnte schon heute verschl\u00fcsselten Datenverkehr mitschneiden und speichern \u2013 um ihn Jahre sp\u00e4ter, sobald ausreichend leistungsf\u00e4hige Quantencomputer bereitstehen, zu entschl\u00fcsseln. Dieses Szenario nennt man \u201e<a href=\"https:\/\/en.wikipedia.org\/wiki\/Harvest_now,_decrypt_later\" target=\"_blank\" rel=\"noopener\">Harvest now, decrypt later<\/a>\u201c. Alles, was du heute klassisch verschl\u00fcsselt \u00fcbertr\u00e4gst, ist damit potenziell gef\u00e4hrdet.<\/p>\n\n\n\n<p>Java 27 f\u00fcgt nun quantensichere Verschl\u00fcsselung f\u00fcr TLS (den Nachfolger von SSL) hinzu \u2013 und zwar in Form von sogenanntem <em>hybridem Schl\u00fcsselaustausch<\/em> (englisch: <em>hybrid key exchange<\/em>). Hybrider Schl\u00fcsselaustausch bedeutet, dass mehrere Schl\u00fcsselaustauschverfahren kombiniert werden \u2013 und der Schl\u00fcsselaustausch selbst dann noch sicher ist, wenn alle der verwendeten Verfahren bis auf eines geknackt wurden.<\/p>\n\n\n\n<p>In der Java-Implementierung wird je ein <a href=\"https:\/\/de.wikipedia.org\/wiki\/Diffie-Hellman-Schl%C3%BCsselaustausch#Elliptic_Curve_Diffie-Hellman_(ECDH)\" target=\"_blank\" rel=\"noopener\">ECDHE<\/a>-Algorithmus (nicht quantensicher) mit einem <a href=\"https:\/\/de.wikipedia.org\/wiki\/Kyber_(Kryptosystem)\" target=\"_blank\" rel=\"noopener\">ML-KEM<\/a>-Algorithmus (quantensicher) kombiniert \u2013 in drei Varianten mit jeweils unterschiedlichen Schl\u00fcssell\u00e4ngen.<\/p>\n\n\n\n<p>Sofern vom Server unterst\u00fctzt, setzt Java 27 den neuen, quantensicheren Schl\u00fcsselaustausch automatisch ein \u2013 ohne dass es einer speziellen Konfiguration bedarf. So l\u00e4sst sich aufgezeichneter Datenverkehr auch mit einem k\u00fcnftigen Quantencomputer nicht mehr entschl\u00fcsseln.<\/p>\n\n\n\n<p>Welche Varianten der Algorithmen genau eingesetzt werden \u2013 und wie du beim Aufbau einer TLS-Verbindung die Standard-Algorithmen-Auswahl von Java \u00fcberschreiben kannst, kannst du in <a href=\"https:\/\/openjdk.org\/jeps\/527\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 527<\/a> nachlesen. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"make-g1-the-default-garbage-collector-in-all-environments-jep-523\">Make G1 the Default Garbage Collector in All Environments \u2013 JEP 523<\/h2>\n\n\n\n<p>Der G1 Garbage Collector ist seit Java 9 der Default-Garbage-Collector \u2013 <em>in der Regel<\/em>. Eine Ausnahme galt bisher f\u00fcr leistungsschwache Maschinen mit entweder nur einer CPU oder weniger als 1.792 MB RAM. Auf solchen Maschinen wurde standardm\u00e4\u00dfig der Serial GC aktiviert, da dieser mit diesen begrenzten Ressourcen einen signifikant h\u00f6heren Durchsatz und niedrigeren Speicherverbrauch hatte als der G1.<\/p>\n\n\n\n<p>Durch die kontinuierlichen Verbesserungen am G1 \u2013 zuletzt durch die <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/#g1-gc-improve-throughput-by-reducing-synchronization-jep-522\">Verbesserungen des Durchsatzes in Java 26<\/a> \u2013 erreicht der G1 auch auf leistungsschw\u00e4cheren Maschinen nun ann\u00e4hernd den Durchsatz des Serial GC. <\/p>\n\n\n\n<p>Da die Latenzen des G1 grunds\u00e4tzlich besser sind als die des Serial GC, entschied das JDK-Team nun, die Ausnahmeregel f\u00fcr leistungsschwache Maschinen zu entfernen und den G1 in allen Umgebungen \u2013 unabh\u00e4ngig von CPU-Anzahl und Speichergr\u00f6\u00dfe \u2013 zum Default-Garbage-Collector zu machen.<\/p>\n\n\n\n<p>Es ist nicht geplant, den Serial GC zu entfernen; dieser kann (genau wie zuvor dort, wo er nicht standardm\u00e4\u00dfig ausgew\u00e4hlt wurde) \u00fcber <code>-XX:+UseSerialGC<\/code> aktiviert werden.<\/p>\n\n\n\n<p>Die \u00c4nderung ist in <a href=\"https:\/\/openjdk.org\/jeps\/523\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 523<\/a> spezifiziert.<\/p>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"wiedervorgelegte-preview-und-incubator-features\">Wiedervorgelegte Preview- und Incubator-Features<\/h2>\n\n\n\n<p>In Java 27 werden die folgenden vier Preview-Features sowie ein Incubator-Feature wiedervorgelegt \u2013 teilweise mit kleineren \u00c4nderungen, teilweise ganz ohne \u00c4nderungen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"lazy-constants-third-preview-jep-531\">Lazy Constants (Third Preview) \u2013 JEP 531<\/h3>\n\n\n\n<p>Lazy Constants kennst du vielleicht noch unter einem anderen Namen: In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-25-features\/#stable-values-preview-jep-502\">Java 25<\/a> wurden sie als <em>Stable Values<\/em> eingef\u00fchrt. In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/#lazy-constants-second-preview-jep-526\">Java 26<\/a> hat das JDK-Team die API nach reichlich Feedback deutlich abgespeckt und in <em>Lazy Constants<\/em> umbenannt (JEP 526). <\/p>\n\n\n\n<p>Wenn du Lazy Constants bereits aus den Vorg\u00e4ngerversionen kennst und nur wissen willst, was sich in Java 27 \u00e4ndert, springe direkt zum Abschnitt Lazy Constants \u2013 \u00c4nderungen in Java 27.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Welches Problem l\u00f6sen Lazy Constants?<\/h4>\n\n\n\n<p>Konstanten \u2013 also Werte, die sich nach ihrer Initialisierung nicht mehr \u00e4ndern \u2013 bringen gleich mehrere Vorteile mit: Der Code wird einfacher und sicherer, denn eine Konstante kennt nur einen einzigen Zustand und l\u00e4sst sich gefahrlos aus mehreren Threads heraus lesen. Zudem kann die JVM den Zugriff auf sie durch sogenanntes Constant Folding optimieren.<\/p>\n\n\n\n<p>Bisher gibt es nur einen Weg, eine Konstante zu definieren \u2013 \u00fcber ein finales Feld:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ein finales statisches Feld, das beim Laden der Klasse gesetzt wird, oder<\/li>\n\n\n\n<li>ein finales Instanzfeld, das beim Erzeugen des Objekts gesetzt wird.<\/li>\n<\/ul>\n\n\n\n<p>Was aber, wenn du einen unver\u00e4nderlichen Wert erst dann berechnen willst, wenn er wirklich gebraucht wird \u2013 etwa weil seine Initialisierung aufw\u00e4ndig ist? Dann bleibt dir nur die \u201eLazy Initialization\u201c. Und damit die in einer nebenl\u00e4ufigen Anwendung korrekt funktioniert, musstest du sie bislang m\u00fchsam mit dem <a href=\"https:\/\/www.happycoders.eu\/de\/java\/double-checked-locking\/\">Double-Checked-Locking<\/a> oder dem <a href=\"https:\/\/www.happycoders.eu\/de\/java\/initialization-on-demand-holder-idiom\/\">Initialization-on-Demand-Holder-Idiom<\/a> absichern. Wer das einmal von Hand geschrieben hat, wei\u00df: Dabei schleichen sich selbst bei erfahrenen Entwickler:innen schnell Fehler ein.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Die Lazy-Constants-API<\/h4>\n\n\n\n<p>Genau hier setzt die API an. Eine Lazy Constant ist ein Container f\u00fcr genau einen Wert, der h\u00f6chstens einmal berechnet und danach wie eine echte Konstante behandelt wird.<\/p>\n\n\n\n<p>Im folgenden Beispiel definieren wir eine <code>LazyConstant<\/code>, die beim ersten Zugriff einen Bean-Validation-Validator erzeugt \u2013 ein Objekt, dessen Erzeugung teuer ist, weshalb wir es nicht direkt beim Programmstart erzeugen wollen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> LazyConstant&lt;Validator&gt; validator =\n        LazyConstant.of(<span class=\"hljs-keyword\">this<\/span>::createValidator);\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> Validator <span class=\"hljs-title\">createValidator<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> Validation.buildDefaultValidatorFactory().getValidator();\n}\n\n<span class=\"hljs-keyword\">public<\/span> Set&lt;ConstraintViolation&lt;Order&gt;&gt; validate(Order order) {\n    <span class=\"hljs-keyword\">return<\/span> validator.get().validate(order); <span class=\"hljs-comment\">\/\/ &lt;-- Hier greifen wir auf die Lazy Constant zu<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Erst der erste Aufruf von <code>validator.get()<\/code> f\u00fchrt <code>createValidator()<\/code> aus. Das Ergebnis wird in der <code>LazyConstant<\/code> abgelegt; jeder weitere Aufruf von <code>validator.get()<\/code> liefert den gespeicherten Validator zur\u00fcck. Um die Threadsicherheit musst du dich nicht k\u00fcmmern: Selbst wenn mehrere Threads gleichzeitig auf <code>validator.get()<\/code> zugreifen, wird <code>createValidator()<\/code> garantiert h\u00f6chstens einmal ausgef\u00fchrt.<\/p>\n\n\n\n<p>Sobald die Lazy Constant initialisiert ist, betrachtet die JVM sie als unver\u00e4nderlich und optimiert den Zugriff per Constant Folding \u2013 als h\u00e4ttest du den Wert von Anfang an in ein finales Feld geschrieben.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Lazy Lists<\/h4>\n\n\n\n<p>Du kannst nicht nur einzelne Lazy Constants definieren, sondern auch ganze Listen davon \u2013 Listen also, bei denen jedes Element eine eigene Lazy Constant ist. Das folgende Beispiel legt f\u00fcr ein Dokument pro Seite ein Vorschaubild an, von denen jedes aber erst beim ersten Zugriff darauf gerendert wird:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> List&lt;Thumbnail&gt; thumbnails =\n        List.ofLazy(document.pageCount(), <span class=\"hljs-keyword\">this<\/span>::renderThumbnail);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>renderThumbnail()<\/code> wird also nicht f\u00fcr alle Seiten des Dokuments auf einmal aufgerufen, sondern separat pro Element der <code>thumbnails<\/code>-Liste \u2013 etwa beim direkten Zugriff \u00fcber <code>get(int index)<\/code> oder beim Iterieren \u00fcber die Liste. Greifst du nur auf die ersten drei Seiten zu, werden auch nur drei Vorschaubilder gerendert. Auch hier ist die Initialisierung threadsicher \u2013 und nach dem ersten Zugriff behandelt die JVM auch hier die Werte wie Konstanten.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Lazy Maps<\/h4>\n\n\n\n<p>Auch Maps lassen sich verz\u00f6gert initialisieren. Bei einer Lazy Map stehen die Schl\u00fcssel beim Erzeugen bereits fest, die zugeh\u00f6rigen Werte werden aber erst bei Bedarf berechnet. Das folgende Beispiel ordnet W\u00e4hrungscodes ihre Wechselkurse zu, die wir \u00fcber einen externen Dienst abrufen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Set&lt;String&gt; currencies = Set.of(<span class=\"hljs-string\">\"USD\"<\/span>, <span class=\"hljs-string\">\"GBP\"<\/span>, <span class=\"hljs-string\">\"JPY\"<\/span>, <span class=\"hljs-string\">\"CHF\"<\/span>);\nMap&lt;String, BigDecimal&gt; exchangeRates =\n        Map.ofLazy(currencies, <span class=\"hljs-keyword\">this<\/span>::fetchExchangeRate);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Erst beim ersten Zugriff auf einen bestimmten W\u00e4hrungscode \u2013 z. B. \u00fcber <code>exchangeRates.get(\"JPY\")<\/code> \u2013 wird <code>fetchExchangeRate()<\/code> f\u00fcr diesen Key aufgerufen und das Ergebnis als Konstante in der Map abgelegt. Fragst du nie einen Yen-Kurs ab, wird er auch nie geladen. Wie schon bei Lazy Constants und Lazy Lists ist auch die Lazy Map threadsicher.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Lazy Sets<\/h4>\n\n\n\n<p>Und damit zur eigentlichen Neuerung in Java 27: Lazy Sets. Bei einem Lazy Set \u00fcbergibst du eine Menge m\u00f6glicher Kandidaten sowie eine Funktion, die f\u00fcr jeden Kandidaten entscheidet, ob er tats\u00e4chlich zur Menge geh\u00f6rt. Diese Funktion wird erst beim ersten Test eines Elements ausgef\u00fchrt.<\/p>\n\n\n\n<p>Das folgende Beispiel pr\u00fcft, welche Features f\u00fcr die aktuelle Anwendung freigeschaltet sind. Die m\u00f6glichen Features stehen fest; ob ein Feature aktiv ist, kl\u00e4rt eine (m\u00f6glicherweise teure) Abfrage gegen einen Feature-Flag-Service:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Set&lt;String&gt; candidates =\n        Set.of(<span class=\"hljs-string\">\"dark-mode\"<\/span>, <span class=\"hljs-string\">\"beta-export\"<\/span>, <span class=\"hljs-string\">\"ai-assistant\"<\/span>, <span class=\"hljs-string\">\"live-collab\"<\/span>);\n\nSet&lt;String&gt; enabledFeatures =\n        Set.ofLazy(candidates, <span class=\"hljs-keyword\">this<\/span>::isFeatureEnabled);\n\n<span class=\"hljs-keyword\">if<\/span> (enabledFeatures.contains(<span class=\"hljs-string\">\"ai-assistant\"<\/span>)) { <span class=\"hljs-comment\">\/\/ \u27f5 erst hier wird isFeatureEnabled(\"ai-assistant\") aufgerufen<\/span>\n    <span class=\"hljs-comment\">\/\/ ...<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Methode <code>isFeatureEnabled()<\/code> wird nur f\u00fcr diejenigen Features ausgef\u00fchrt, die du auch wirklich abfragst \u2013 und das pro Element h\u00f6chstens einmal \u2013 und das ganze wiederum threadsicher.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Lazy Constants \u2013 \u00c4nderungen in Java 27<\/h4>\n\n\n\n<p>In Java 27 werden durch <a href=\"https:\/\/openjdk.org\/jeps\/531\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 531<\/a> zwei \u00c4nderungen vorgenommen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die Low-Level-Methoden <code>isInitialized()<\/code> und <code>orElse()<\/code> entfallen. Sie verleiteten dazu, Lazy Constants gegen ihre eigentliche Designidee einzusetzen \u2013 etwa, um abh\u00e4ngig vom Initialisierungszustand unterschiedlich zu reagieren. Genau das soll eine Lazy Constant aber nicht leisten.<\/li>\n\n\n\n<li>Zweitens kommt \u2013 wie oben gezeigt \u2013 die neue Factory-Methode <code>Set.ofLazy()<\/code> hinzu. Damit gibt es nun f\u00fcr alle drei grundlegenden Collection-Typen \u2013 <code>List<\/code>, <code>Set<\/code> und `Map` \u2013 eine Lazy-Variante.<\/li>\n<\/ul>\n\n\n\n<p>Mehr Beispiele und Details findest du im <a href=\"https:\/\/www.happycoders.eu\/de\/java\/lazy-constants\/\">Hauptartikel \u00fcber Lazy Constants<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"primitive-types-in-patterns-instanceof-and-switch-fifth-preview-jep-532\">Primitive Types in Patterns, instanceof, and switch (Fifth Preview) \u2013 JEP 532<\/h3>\n\n\n\n<p>Pattern Matching mit primitiven Typen wurde in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-23-features\/#primitive-types-in-patterns-instanceof-and-switch-preview-jep-455\">Java 23<\/a> als Preview-Feature vorgestellt. In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/#primitive-types-in-patterns-instanceof-and-switch-fourth-preview-jep-530\">Java 26<\/a> gab es einige Verbesserungen in der Dominanzpr\u00fcfung. In Java 27 wird das Feature durch <a href=\"https:\/\/openjdk.org\/jeps\/532\">JDK Enhancement Proposal 532<\/a> \u2013 erneut ohne \u00c4nderungen \u2013 in eine f\u00fcnfte Preview-Runde geschickt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Pattern Matching und switch mit primitiven Typen \u2013 Status quo<\/h4>\n\n\n\n<p>Pattern Matching funktioniert bislang ausschlie\u00dflich mit Referenztypen, etwa so:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Object obj = . . .\n<span class=\"hljs-keyword\">switch<\/span> (obj) {\n    <span class=\"hljs-keyword\">case<\/span> String s when s.length() &gt; <span class=\"hljs-number\">10<\/span> -&gt; IO.println(<span class=\"hljs-string\">\"langer String\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> Character c                   -&gt; IO.println(Character.toUpperCase(c));\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">null<\/span>, <span class=\"hljs-keyword\">default<\/span>                 -&gt; IO.println(obj);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Ein <code>switch<\/code> \u00fcber primitive Typen gibt es auch \u2013 aber bisher nur f\u00fcr <code>byte<\/code>, <code>short<\/code>, <code>char<\/code> und <code>int<\/code>. Und in den <code>case<\/code>-Labels d\u00fcrfen ausschlie\u00dflich Konstanten stehen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">int<\/span> port = . . .\n<span class=\"hljs-keyword\">switch<\/span> (port) {\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-number\">80<\/span>  -&gt; IO.println(<span class=\"hljs-string\">\"HTTP\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-number\">443<\/span> -&gt; IO.println(<span class=\"hljs-string\">\"HTTPS\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Pattern Matching und switch mit primitiven Typen \u2013 was sich \u00e4ndert<\/h4>\n\n\n\n<p>K\u00fcnftig sollen sich alle primitiven Typen im <code>switch<\/code> verwenden lassen, also auch <code>long<\/code>, <code>double<\/code>, <code>float<\/code> und sogar <code>boolean<\/code>. Au\u00dferdem sollen in den <code>case<\/code>-Labels nicht mehr nur Konstanten, sondern auch Patterns erlaubt sein. Damit k\u00f6nnten wir beispielsweise einen <code>int<\/code>-Wert auf bestimmte Bereiche pr\u00fcfen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">int<\/span> score = . . .\n<span class=\"hljs-keyword\">switch<\/span> (score) {\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">int<\/span> s when s &gt;= <span class=\"hljs-number\">90<\/span> -&gt; IO.println(<span class=\"hljs-string\">\"sehr gut\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">int<\/span> s when s &gt;= <span class=\"hljs-number\">75<\/span> -&gt; IO.println(<span class=\"hljs-string\">\"gut\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">int<\/span> s when s &gt;= <span class=\"hljs-number\">60<\/span> -&gt; IO.println(<span class=\"hljs-string\">\"befriedigend\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">int<\/span> s when s &gt;= <span class=\"hljs-number\">50<\/span> -&gt; IO.println(<span class=\"hljs-string\">\"ausreichend\"<\/span>);\n    <span class=\"hljs-keyword\">default<\/span>                 -&gt; IO.println(<span class=\"hljs-string\">\"nicht bestanden\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Patterns mit Referenztypen matchen auch auf Untertypen \u2013 ein <code>case Number n<\/code> w\u00fcrde also genauso ein <code>Integer<\/code>-Objekt erfassen. Bei primitiven Typen gibt es jedoch keine Vererbung. Die JDK-Entwickler:innen haben sich f\u00fcr diesen Fall daher etwas anderes \u00fcberlegt:<\/p>\n\n\n\n<p>Wir k\u00f6nnen k\u00fcnftig mit <code>switch<\/code> \u2013 und genauso mit <code>instanceof<\/code> \u2013 pr\u00fcfen, ob sich der Wert einer primitiven Variablen ohne Pr\u00e4zisionsverlust in einem anderen primitiven Typ darstellen l\u00e4sst:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">double<\/span> value = . . .\n<span class=\"hljs-keyword\">switch<\/span> (value) {\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">byte<\/span>   b -&gt; IO.println(value + <span class=\"hljs-string\">\" instanceof byte:   \"<\/span> + b);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">short<\/span>  s -&gt; IO.println(value + <span class=\"hljs-string\">\" instanceof short:  \"<\/span> + s);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">char<\/span>   c -&gt; IO.println(value + <span class=\"hljs-string\">\" instanceof char:   \"<\/span> + c);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">int<\/span>    i -&gt; IO.println(value + <span class=\"hljs-string\">\" instanceof int:    \"<\/span> + i);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">long<\/span>   l -&gt; IO.println(value + <span class=\"hljs-string\">\" instanceof long:   \"<\/span> + l);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">float<\/span>  f -&gt; IO.println(value + <span class=\"hljs-string\">\" instanceof float:  \"<\/span> + f);\n    <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">double<\/span> d -&gt; IO.println(value + <span class=\"hljs-string\">\" instanceof double: \"<\/span> + d);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>H\u00e4tte <code>value<\/code> hier den Wert <code>100<\/code>, w\u00fcrde das Pattern <code>byte b<\/code> matchen, denn <code>100<\/code> passt verlustfrei in ein <code>byte<\/code>. Bei <code>40_000<\/code> w\u00fcrde <code>char c<\/code> matchen, bei <code>100_000<\/code> das Pattern <code>int i<\/code>. Ein Wert wie <code>0.25<\/code> matcht auf <code>float f<\/code> \u2013 denn diese Zahl l\u00e4sst sich exakt als <code>float<\/code> darstellen. <code>0.1<\/code> hingegen matcht nur auf <code>double d<\/code>, weil sich dieser Wert eben <em>nicht<\/em> pr\u00e4zise in einem <code>float<\/code> darstellen l\u00e4sst.<\/p>\n\n\n\n<p>Auch bei primitiven Typen gilt das Dominanzprinzip: Die Reihenfolge der <code>case<\/code>-Label im obigen Beispiel ist nicht beliebig. W\u00fcrden wir sie \u00e4ndern, w\u00e4ren einzelne Labels nicht mehr erreichbar. <code>int i<\/code> d\u00fcrfte zum Beispiel nicht vor <code>byte b<\/code> stehen, denn jeder m\u00f6gliche Byte-Wert w\u00fcrde bereits auf <code>int i<\/code> matchen.<\/p>\n\n\n\n<p>Mehr zu den genauen Regeln und weitere Beispiele und Besonderheiten findest du im <a href=\"https:\/\/www.happycoders.eu\/de\/java\/primitive-type-patterns\/\">Hauptartikel Primitive Typen in Patterns, instanceof und switch<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"structured-concurrency-seventh-preview-jep-533\">Structured Concurrency (Seventh Preview) \u2013 JEP 533<\/h3>\n\n\n\n<p>Structured Concurrency geht mittlerweile in die siebte Preview-Runde. Falls du die API bereits kennst und nur wissen m\u00f6chtest, was sich in Java 27 ge\u00e4ndert hat, springst du am besten direkt zum Abschnitt \u201e<a href=\"#structured-concurrency-aenderungen-in-java-27\">Structured Concurrency \u2013 \u00c4nderungen in Java 27<\/a>\u201c.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Was ist <em>Unstructured<\/em> Concurrency?<\/h4>\n\n\n\n<p>Wer fr\u00fcher mit <code>GOTO<\/code> programmiert hat, wei\u00df, was <em>unstrukturierte Programmierung<\/em> ist: Mit <code>GOTO<\/code> konnten wir an eine beliebige Stelle im Programmcode springen \u2013 ohne jemals wieder an die aufrufende Stelle zur\u00fcckzukehren. Das resultierte in der Regel in schlecht lesbarem, sogenannten Spaghetti-Code. Durch die Einf\u00fchrung von <em>strukturierter <\/em>Programmierung wurde <code>GOTO<\/code> eliminiert und durch Schleifen, If-Then-Else-Bl\u00f6cke und Methodenaufrufe ersetzt \u2013 Kontrollstrukturen mit klar erkennbaren Einstiegs- und Ausstiegspunkten.<\/p>\n\n\n\n<p><em>Unstructured Concurrency<\/em> \u00fcbertr\u00e4gt dieses Modell auf die Nebenl\u00e4ufigkeit: Wir starten Threads, wobei oft im Code nicht klar erkennbar ist, wann diese Threads wieder enden. Manchmal warten wir mit <code>join()<\/code> darauf, dass ein Thread endet, manchmal nicht. Manchmal fahren wir einen <code>ExecutorService<\/code> sauber mit <code>shutdown()<\/code> und <code>awaitTermination()<\/code> herunter, manchmal nicht.<\/p>\n\n\n\n<p>Grafisch l\u00e4sst sich das etwa so darstellen:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-half_400\"><img decoding=\"async\" width=\"400\" height=\"341\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2-400x341.png\" alt=\"Unstructured Concurrency\" class=\"wp-image-37257\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2-400x341.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2-224x191.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2-336x286.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2-504x430.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2-672x573.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2-600x512.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/09\/unstructured-concurrency.v2.png 800w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><figcaption class=\"wp-element-caption\">Unstructured Concurrency<\/figcaption><\/figure>\n<\/div>\n\n\n<h4 class=\"wp-block-heading\">Was ist Structured Concurrency?<\/h4>\n\n\n\n<p><em>Structured Concurrency<\/em> \u00fcbertr\u00e4gt das Prinzip der strukturierten Programmierung auf die Nebenl\u00e4ufigkeit: S\u00e4mtliche Ausf\u00fchrungspfade, die beim Starten nebenl\u00e4ufiger Tasks aufgespannt werden, laufen an einer einzigen Stelle im Code wieder zusammen. Und an dieser Stelle ist garantiert, dass kein verwaister Thread mehr im Hintergrund weiterarbeitet:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-half_400\"><img decoding=\"async\" width=\"400\" height=\"400\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency-400x400.png\" alt=\"JEP 499 Structured Concurrency in Java\" class=\"wp-image-42208\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency-400x400.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency-224x224.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency-336x336.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency-504x504.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency-672x672.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency-600x600.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/12\/jep499-structured-concurrency.png 800w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><figcaption class=\"wp-element-caption\">Structured Concurrency<\/figcaption><\/figure>\n<\/div>\n\n\n<h4 class=\"wp-block-heading\">Structured Concurrency in Java<\/h4>\n\n\n\n<p>Im Ansatz war das in Java schon m\u00f6glich \u2013 etwa mit einem <code>ExecutorService<\/code> und einem anschlie\u00dfenden Aufruf von <code>close()<\/code> bzw. <code>shutdown()<\/code> und <code>awaitTermination()<\/code> \u2013 oder seit Java 19 durch das \u00d6ffnen eines <code>ExecutorService<\/code> in einem Try-with-Resources-Block (welcher am Ende wiederum automatisch <code>close()<\/code> aufruft).<\/p>\n\n\n\n<p>Doch die Structured-Concurrency-API <code>StructuredTaskScope<\/code> geht sp\u00fcrbar weiter: Sie kann einen Scope beim Eintreten bestimmter Ereignisse vorzeitig beenden und alle noch laufenden Tasks abbrechen. Mit einem <code>ExecutorService<\/code> lie\u00df sich das nur \u00fcber eine extrem aufw\u00e4ndige und fehleranf\u00e4llige Orchestrierung nachbilden, in der Gesch\u00e4ftslogik, Thread-Handling und Error-Handling so miteinander verzahnt waren, dass die Gesch\u00e4ftslogik kaum noch erkennbar war.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Die StructuredTaskScope-API<\/h4>\n\n\n\n<p>Mit <code>StructuredTaskScope<\/code> geht das deutlich einfacher. Der folgende Code startet drei Subtasks parallel und wartet anschlie\u00dfend mit <code>scope.join()<\/code>, bis alle drei fertig sind. Schl\u00e4gt einer der Subtasks fehl, werden die \u00fcbrigen abgebrochen \u2013 und <code>scope.join()<\/code> wirft eine <code>ExecutionException<\/code> mit der urspr\u00fcnglich aufgetretenen Exception als Cause:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\">ProductPage <span class=\"hljs-title\">loadProductPage<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">long<\/span> productId)<\/span>\n        <span class=\"hljs-keyword\">throws<\/span> InterruptedException, ExecutionException <\/span>{\n    <span class=\"hljs-keyword\">try<\/span> (<span class=\"hljs-keyword\">var<\/span> scope = StructuredTaskScope.open()) {\n        <span class=\"hljs-keyword\">var<\/span> detailsTask = scope.fork(() -&gt; catalogService.getDetails(productId));\n        <span class=\"hljs-keyword\">var<\/span> priceTask   = scope.fork(() -&gt; pricingService.getPrice(productId));\n        <span class=\"hljs-keyword\">var<\/span> stockTask   = scope.fork(() -&gt; inventoryService.getStock(productId));\n        scope.join();\n        <span class=\"hljs-keyword\">return<\/span> ProductPage.assemble(\n                detailsTask.get(), priceTask.get(), stockTask.get());\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Manchmal brauchen wir aber gar nicht die Ergebnisse <em>aller<\/em> Subtasks, sondern nur das <em>erste<\/em>, das eintrifft. Daf\u00fcr k\u00f6nnen wir die Strategie des <code>StructuredTaskScopes<\/code> \u00e4ndern, indem wir der <code>open()<\/code>-Methode einen sogenannten <em>Joiner <\/em>mitgeben. Im folgenden Beispiel fragen wir dieselbe Adresse bei drei redundanten Geocoding-Diensten ab \u2013 und sobald<em> einer<\/em> ein Ergebnis liefert, werden die beiden anderen abgebrochen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\">GeoCoordinates <span class=\"hljs-title\">resolveAddress<\/span><span class=\"hljs-params\">(String address)<\/span>\n        <span class=\"hljs-keyword\">throws<\/span> InterruptedException, ExecutionException <\/span>{\n    <span class=\"hljs-keyword\">try<\/span> (<span class=\"hljs-keyword\">var<\/span> scope = StructuredTaskScope.open(\n            Joiner.&lt;GeoCoordinates&gt;anySuccessfulOrThrow())) {\n        scope.fork(() -&gt; primaryGeocoder.lookup(address));\n        scope.fork(() -&gt; backupGeocoder.lookup(address));\n        scope.fork(() -&gt; offlineGeocoder.lookup(address));\n        <span class=\"hljs-keyword\">return<\/span> scope.join();\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Das <code>Joiner<\/code>-Interface stellt noch weitere Strategien bereit \u2013 und du kannst auch eigene implementieren. Welche das sind und wie du dabei vorgehst, erf\u00e4hrst du im <a href=\"https:\/\/www.happycoders.eu\/de\/java\/structured-concurrency-structuredtaskscope\/\">Hauptartikel \u00fcber Structured Concurrency in Java<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"structured-concurrency-aenderungen-in-java-27\">Structured Concurrency \u2013 \u00c4nderungen in Java 27<\/h4>\n\n\n\n<p>Erstmals vorgestellt wurde Structured Concurrency als Incubator-Feature zusammen mit <a href=\"https:\/\/www.happycoders.eu\/de\/java\/virtual-threads\/\">virtuellen Threads<\/a> in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-19-features\/#structured-concurrency-incubator-jep-428\">Java 19<\/a>. In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-25-features\/#structured-concurrency-fifth-preview-jep-505\">Java 25<\/a> wurde die API grundlegend \u00fcberarbeitet (Stichwort \u201eComposition over Inheritance\u201c), in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/#structured-concurrency-sixth-preview-jep-525\">Java 26<\/a> folgten einige kleinere Anpassungen. Mit Java 27 bringt <a href=\"https:\/\/openjdk.org\/jeps\/533\">JDK Enhancement Proposal 533<\/a> die folgenden \u00c4nderungen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die Joiner <code>allSuccessfulOrThrow()<\/code>, <code>anySuccessfulOrThrow()<\/code> und <code>awaitAllSuccessfulOrThrow()<\/code> werfen beim Fehlschlagen eines Subtasks nicht mehr die Preview-spezifische <code>FailedException<\/code>, sondern eine <code>ExecutionException<\/code> \u2013 also die gleiche Wrapper-Exception, die auch <code>Future.get()<\/code> werfen kann. Die urspr\u00fcngliche Exception steckt wie gewohnt in <code>getCause()<\/code>.<\/li>\n\n\n\n<li><code>StructuredTaskScope<\/code> und <code>Joiner<\/code> haben einen dritten Typparameter <code>R_X<\/code> bekommen, der f\u00fcr den Exception-Typ steht, den <code>join()<\/code> werfen kann. Aus <code>Joiner&lt;T, R&gt;<\/code> wird damit <code>Joiner&lt;T, R, R_X&gt;<\/code>. Wenn du die mitgelieferten Joiner \u00fcber <code>open()<\/code> verwendest, leitet der Compiler die Typen in der Regel selbst ab \u2013 dein Code sieht unver\u00e4ndert aus. Sichtbar wird der Unterschied erst, wenn du eigene Joiner schreibst.<\/li>\n\n\n\n<li>Die in Java 26 eingef\u00fchrte <code>Joiner<\/code>-Methode <code>onTimeout()<\/code> hei\u00dft jetzt <code>timeout()<\/code>. Sie wird aufgerufen, wenn der Scope durch einen Timeout abgebrochen wird, und liefert dann entweder ein Ergebnis oder wirft eine Exception.<\/li>\n\n\n\n<li>Der Joiner <code>awaitAll()<\/code> wurde entfernt.<\/li>\n\n\n\n<li>Es gibt eine neue <code>StructuredTaskScope.open()<\/code>-Methode, die die Standard-Join-Strategie (alle Subtasks abwarten, beim ersten Fehler abbrechen) mit einem Konfigurations-Operator kombiniert. Bisher musstest du, um dem Scope beispielsweise einen Timeout und einen Namen mitzugeben, zus\u00e4tzlich den Standard-Joiner \u00fcbergeben. Das entf\u00e4llt jetzt:<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> (<span class=\"hljs-keyword\">var<\/span> scope = StructuredTaskScope.open(\n        cfg -&gt; cfg.withTimeout(Duration.ofSeconds(<span class=\"hljs-number\">2<\/span>)).withName(<span class=\"hljs-string\">\"checkout\"<\/span>))) {\n    scope.fork(() -&gt; cartService.getCart(userId));\n    scope.fork(() -&gt; profileService.getProfile(userId));\n    scope.join();\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Code, der f\u00fcr Java 26 geschrieben wurde, l\u00e4sst sich also mit \u00fcberschaubarem Aufwand auf Java 27 \u00fcbertragen \u2013 der h\u00e4ufigste Eingriff wird sein, ein <code>catch (FailedException ...)<\/code> auf <code>catch (ExecutionException ...)<\/code> umzustellen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"pem-encodings-of-cryptographic-objects-third-preview-jep-538\">PEM Encodings of Cryptographic Objects (Third Preview) \u2013 JEP 538<\/h3>\n\n\n\n<p>PEM ist die Abk\u00fcrzung f\u00fcr Privacy-Enhanced Mail \u2013 ein Kodierungsschema, mit dem sich kryptografische Objekte als Text darstellen lassen, der sich per Mail verschicken l\u00e4sst. PEM-kodierte Objekte sind dir sicher schon einmal begegnet \u2013 etwa in Form eines Zertifikats wie diesem:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">-----BEGIN CERTIFICATE-----\nMIIDtzCCAz2gAwIBAgISBUCeYELtjMmr4FAIqHapebbFMAoGCCqGSM49BAMDMDIx\nCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF\n. . .\nDBeMde1YpWNXpF9+B\/OMKgn7RgXRj5b2QpBCnFsP92T4cK\/Nn+xFIjYCMCCx4E79\ntoSQBlYnNHv0eXnWkI8TmXsU\/A6rU4Gxdr9GbGixgRJvkw0C6zjL\/lH2Vg==\n-----END CERTIFICATE-----<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Bislang war es in Java \u00fcberraschend m\u00fchsam, solche PEM-kodierten Objekte zu lesen oder zu schreiben. Das folgende Beispiel zeigt, wie viel Aufwand n\u00f6tig war, um einen PEM-kodierten privaten Schl\u00fcssel einzulesen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String encryptedPrivateKeyPemEncoded = . . .\nString passphrase = . . .\n\nString encryptedPrivateKeyBase64Encoded = encryptedPrivateKeyPemEncoded\n        .replace(<span class=\"hljs-string\">\"-----BEGIN ENCRYPTED PRIVATE KEY-----\"<\/span>, <span class=\"hljs-string\">\"\"<\/span>)\n        .replace(<span class=\"hljs-string\">\"-----END ENCRYPTED PRIVATE KEY-----\"<\/span>, <span class=\"hljs-string\">\"\"<\/span>)\n        .replaceAll(<span class=\"hljs-string\">\"&#091;\\\\r\\\\n]\"<\/span>, <span class=\"hljs-string\">\"\"<\/span>);\n\nBase64.Decoder decoder = Base64.getDecoder();\n<span class=\"hljs-keyword\">byte<\/span>&#091;] encryptedPrivateKeyBytes = decoder.decode(encryptedPrivateKeyBase64Encoded);\nEncryptedPrivateKeyInfo encryptedPrivateKeyInfo =\n        <span class=\"hljs-keyword\">new<\/span> EncryptedPrivateKeyInfo(encryptedPrivateKeyBytes);\n\nString algorithmName = encryptedPrivateKeyInfo.getAlgName();\nSecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithmName);\n\nPBEKeySpec pbeKeySpec = <span class=\"hljs-keyword\">new<\/span> PBEKeySpec(passphrase.toCharArray());\nKey pbeKey = secretKeyFactory.generateSecret(pbeKeySpec);\n\nCipher cipher = Cipher.getInstance(algorithmName);\nAlgorithmParameters algParams = encryptedPrivateKeyInfo.getAlgParameters();\ncipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);\n\nKeyFactory rsaKeyFactory = KeyFactory.getInstance(<span class=\"hljs-string\">\"RSA\"<\/span>);\nKeySpec keySpec = encryptedPrivateKeyInfo.getKeySpec(cipher);\nPrivateKey privateKey = rsaKeyFactory.generatePrivate(keySpec);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Mit Java 25 hielt eine eigene PEM-API Einzug \u2013 zun\u00e4chst als Preview-Feature (JEP 470), das den Umgang mit PEM-kodierten Objekten sp\u00fcrbar vereinfachen sollte. In Java 26 ging die API in die zweite Preview-Runde (JEP 524), und in Java 27 folgt nun die dritte Preview (JEP 538).<\/p>\n\n\n\n<p>Den verschl\u00fcsselten Private Key liest du damit in wenigen Zeilen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">PrivateKey privateKey = PEMDecoder.of()\n        .withDecryption(passphrase.toCharArray())\n        .decode(encryptedPrivateKeyPemEncoded, PrivateKey<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>)<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>F\u00fcr den umgekehrten Weg gibt es \u2013 analog zum <code>PEMDecoder<\/code> \u2013 auch einen <code>PEMEncoder<\/code> mit einer <code>encodeToString()<\/code>-Methode:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String encryptedPrivateKeyPemEncoded = PEMEncoder.of()\n        .withEncryption(passphrase.toCharArray())\n        .encodeToString(privateKey);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">\u00c4nderungen in Java 27<\/h4>\n\n\n\n<p>In der dritten Preview-Runde wurden gegen\u00fcber Java 26 einige Klassen, Interfaces und Methoden angepasst. F\u00fcr die hier gezeigten grundlegenden Anwendungsf\u00e4lle sind diese \u00c4nderungen jedoch nicht relevant \u2013 das simple Beispiel oben funktioniert unver\u00e4ndert weiter. <\/p>\n\n\n\n<p>Weitere Details zur PEM API und zu diesen \u00c4nderungen findest du im <a href=\"https:\/\/openjdk.org\/jeps\/538\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 538<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vector-api-twelfth-incubator-jep-537\">Vector API (Twelfth Incubator) \u2013 JEP 537<\/h3>\n\n\n\n<p>Und damit sind wir \u2013 inzwischen zum zw\u00f6lften Mal \u2013 bei der Vector API angelangt. Die Vektor-API erm\u00f6glicht es uns, mathematische Vektoroperationen direkt \u00fcber die Vektor-Befehlss\u00e4tze moderner CPUs \u2013 <a href=\"https:\/\/de.wikipedia.org\/wiki\/Streaming_SIMD_Extensions\" target=\"_blank\" rel=\"noopener\">Streaming SIMD Extensions<\/a> (SSE) bzw. <a href=\"https:\/\/de.wikipedia.org\/wiki\/Advanced_Vector_Extensions\" target=\"_blank\" rel=\"noopener\">Advanced Vector Extensions<\/a> (AVX) \u2013 auszuf\u00fchren und dadurch deutlich performanter zu rechnen als mit klassischem, skalarem Code. Ein typisches Beispiel ist die Addition zweier Vektoren:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-half_400\"><img decoding=\"async\" width=\"400\" height=\"91\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-400x91.png\" alt=\"java vector addition\" class=\"wp-image-25531\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-400x91.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-224x51.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-336x76.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-504x115.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-672x153.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-600x137.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition.png 800w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><figcaption class=\"wp-element-caption\">Beispiel einer Vektoraddition<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Mit der Vector API sieht eine solche Addition wie folgt aus \u2013 <code>a<\/code> und <code>b<\/code> sind die beiden Eingabe-Vektoren, <code>c<\/code> der Ergebnis-Vektor:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">final<\/span> VectorSpecies&lt;Float&gt; SPECIES = FloatVector.SPECIES_PREFERRED;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">addVectors<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">float<\/span>&#091;] a, <span class=\"hljs-keyword\">float<\/span>&#091;] b, <span class=\"hljs-keyword\">float<\/span>&#091;] c)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">int<\/span> i = <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-keyword\">int<\/span> upperBound = SPECIES.loopBound(a.length);\n    <span class=\"hljs-keyword\">for<\/span> (; i &lt; upperBound; i += SPECIES.length()) {\n        <span class=\"hljs-keyword\">var<\/span> va = FloatVector.fromArray(SPECIES, a, i);\n        <span class=\"hljs-keyword\">var<\/span> vb = FloatVector.fromArray(SPECIES, b, i);\n        <span class=\"hljs-keyword\">var<\/span> vc = va.add(vb);\n        vc.intoArray(c, i);\n    }\n    <span class=\"hljs-keyword\">for<\/span> (; i &lt; a.length; i++) {\n        c&#091;i] = a&#091;i] + b&#091;i];\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>F\u00fcr eine derart simple Rechenoperation ist das aktuell noch erstaunlich viel Boilerplate:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>SPECIES.length()<\/code> liefert die Anzahl der Vektor-Elemente, die die CPU in einem einzigen Zyklus parallel verarbeiten kann.<\/li>\n\n\n\n<li><code>SPECIES.loopBound(\u2026)<\/code> ermittelt, wie viele vollst\u00e4ndige Teilvektoren dieser L\u00e4nge sich aus dem Eingabe-Vektor bilden lassen.<\/li>\n\n\n\n<li>Die erste Schleife addiert diese Teilvektoren.<\/li>\n\n\n\n<li>Geht die L\u00e4nge des Eingabe-Vektors nicht glatt auf, bleibt am Ende ein Rest \u00fcbrig \u2013 um diese Elemente zu verarbeiten, brauchen wir eine weitere Schleife.<\/li>\n<\/ul>\n\n\n\n<p>Die zw\u00f6lfte Incubator-Version der Vector API wird durch <a href=\"https:\/\/openjdk.org\/jeps\/537\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 537<\/a> definiert \u2013 und genau wie in Java 26 gibt es auch dieses Mal keine \u00c4nderungen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Status der Vector API<\/h4>\n\n\n\n<p>Warum befindet sich die Vector API \u00fcberhaupt noch im Incubator-Stadium?<\/p>\n\n\n\n<p>Die Klasse <code>Vector<\/code> soll eine sogenannte \u201eValue Class\u201c werden \u2013 das ist eine Klasse, deren Objekte ohne Identit\u00e4t auskommen. An Value Classes wird seit 2014 im Rahmen von <a href=\"https:\/\/openjdk.org\/projects\/valhalla\/\" target=\"_blank\" rel=\"noopener\">Project Valhalla<\/a> gearbeitet. Sobald  der erste JEP aus Project Valhalla, <a href=\"https:\/\/openjdk.org\/jeps\/401\" target=\"_blank\" rel=\"noopener\">JEP 401: Value Classes and Objects<\/a>, als Preview im JDK enthalten sein wird, wird die Vector API auf Value Classes umgestellt und ebenso ins Preview-Stadium \u201ebef\u00f6rdert\u201c werden.<\/p>\n\n\n\n<p>Zur Frage, wann es soweit sein wird, gibt es keine offiziellen Aussagen. Ich habe allerdings auf der <a href=\"https:\/\/jalba.scot\/\" target=\"_blank\" rel=\"noopener\">JAlba<\/a> Mitte Mai 2026 mit zwei hochrangigen Mitarbeitern von Oracle gesprochen, denen ich eine inoffizielle Aussage entlocken konnte: Demnach soll Java 28 eine erste Valhalla-Preview-Version enthalten.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-27\">Sonstige \u00c4nderungen in Java 27<\/h2>\n\n\n\n<p>Nicht alle \u00c4nderungen sind gro\u00df genug, um in einem JEP (JDK Enhancement Proposal) beschrieben zu werden \u2013 zahlreiche kleineren \u00c4nderungen findet ihr daher lediglich in den Release Notes. Ich habe f\u00fcr diesen Abschnitt einige erw\u00e4hnenswerte \u00c4nderungen herausgepickt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"predefined-iso-8601-formatters-support-short-zone-offsets\">Predefined ISO-8601 Formatters Support Short Zone Offsets<\/h3>\n\n\n\n<p>Die <code>DateTimeFormatter.parse()<\/code>-Methode erkennt seit jeher Datumsangaben mit Zeitzonen-Offset, wie z. B. \u201e2026-06-01T22:57:00+02:00\u201c. Dies bedeutet: 1. Juni 2026, 22:57 Uhr mit einem Zeitzonen-Offset von plus 2 Stunden gegen\u00fcber UTC, also 20:57 Uhr UTC.<\/p>\n\n\n\n<p>Das Format ist definiert in <a href=\"https:\/\/de.wikipedia.org\/wiki\/ISO_8601\" target=\"_blank\" rel=\"noopener\">ISO 8601<\/a> und erlaubt die Angabe des Zeitzonen-Offsets auch in einer Kurzform, bei der nur die Stunden angegeben werden, also \u201e2026-06-01T22:57:00<strong>+02<\/strong>\u201c.<\/p>\n\n\n\n<p><code>DateTimeFormatter.parse()<\/code> hat dieses Format bisher als fehlerhaft abgewiesen und eine <code>DateTimeParseException<\/code> geworfen. Ab Java 27 wird das Format unterst\u00fctzt.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung gibt es keinen JEP, sie ist im Bug-Tracker unter <a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8210336\" target=\"_blank\" rel=\"noopener\">JDK-8210336<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"change-the-default-values-of-minheapfreeratio-and-maxheapfreeratio-for-g1\">Change the Default Values of MinHeapFreeRatio and MaxHeapFreeRatio for G1<\/h3>\n\n\n\n<p>Mit den VM-Argumenten <code>-Xms<\/code> und <code>-Xmx<\/code> legen wir den minimalen und maximalen Heap einer Java-Anwendung fest. Mit <code>-XX:MinHeapFreeRatio<\/code> und <code>-XX:MaxHeapFreeRati<\/code>o k\u00f6nnen wir zudem die Schwellen an freiem Heap festlegen unter bzw. \u00fcber denen der Heap vergr\u00f6\u00dfert bzw. verkleinert wird.<\/p>\n\n\n\n<p>Diese Werte lagen bisher bei 40 % und 70 %, d. h. sobald weniger als 40 % Heap frei war, wurde der Heap vergr\u00f6\u00dfert, und sobald mehr als 70 % frei war, wurde der Heap wieder verkleinert.<\/p>\n\n\n\n<p>Da dies zu unn\u00f6tig h\u00e4ufigen Heap-Gr\u00f6\u00dfen\u00e4nderungen f\u00fchrte, wurden diese Werte in Java 27 auf 0 % und 100 % gesetzt. Somit wird der Heap standardm\u00e4\u00dfig nur noch dann vergr\u00f6\u00dfert, wenn er voll ist, und nur dann verkleinert, wenn er leer ist.<\/p>\n\n\n\n<p>Sollte ein anderes Verhalten gew\u00fcnscht sein, kann dies nach wie vor \u00fcber <code>-XX:MinHeapFreeRatio<\/code> und <code>-XX:MaxHeapFreeRati<\/code>o konfiguriert werden.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung gibt es keinen JEP, sie ist im Bug-Tracker unter <a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8238686\" target=\"_blank\" rel=\"noopener\">JDK-8238686<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"rename-xxinitiatingheapoccupancypercent-to-xxg1ihop\">Rename -XX:InitiatingHeapOccupancyPercent to -XX:G1IHOP<\/h3>\n\n\n\n<p>F\u00fcr den Fall, dass du in deiner Anwendung die G1-Option <code>-XX:InitiatingHeapOccupancyPercent<\/code> gesetzt hast (diese konfigurert, wann G1 eine \u201eConcurrent Start collection\u201c ausf\u00fchrt, solange G1 noch nicht ausreichend Daten f\u00fcr eigene Heuristiken gesammelt hat): Diese Option wurde umbenannt in <code>-XX:G1IHOP<\/code>. Der neue Name soll die Tatsache reflektieren, dass dieser Parameter G1-spezifisch ist. Der alte Name wird noch f\u00fcr einige Java-Versionen unterst\u00fctzt werden.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung gibt es keinen JEP, sie ist im Bug-Tracker unter <a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8227106\" target=\"_blank\" rel=\"noopener\">JDK-8227106<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"removal-of-the-jvm-compiler-interface-jvmci\">Removal of the JVM Compiler Interface (JVMCI)<\/h3>\n\n\n\n<p>Das <a href=\"https:\/\/openjdk.org\/jeps\/243\" target=\"_blank\" rel=\"noopener\">in Java 9 eingef\u00fchrte JVM Compiler Interface<\/a> (JVMCI) war eine experimentelle API, mit der die Hotspot-JVM einen in Java geschriebenen Just-In-Time-Compiler ansteuern konnte \u2013 anstelle des eingebauten C2-Compilers. Genau \u00fcber diese Schnittstelle lie\u00df sich beispielsweise der Graal-Compiler als C2-Ersatz in ein normales OpenJDK einklinken (per <code>-XX:+UseGraalJIT<\/code> bzw. <code>-XX:+UseJVMCICompiler<\/code>).<\/p>\n\n\n\n<p>Den experimentellen Graal-Compiler selbst hatte das JDK-Team bereits <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-17-features\/#remove-the-experimental-aot-and-jit-compiler\">in Java 17 entfernt<\/a>; die JVMCI-Schnittstelle blieb damals jedoch erhalten, damit sich extern gebaute Compiler weiterhin einklinken lie\u00dfen. Nach gut zehn Jahren wird nun auch die Schnittstelle selbst eingestellt, da sich ihr Pflege- und Testaufwand f\u00fcr die wenigen verbliebenen Use Cases nicht mehr rechnete.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung gibt es keinen JEP, sie ist im Bug-Tracker unter <a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8382582\" target=\"_blank\" rel=\"noopener\">JDK-8382582<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-27\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 27<\/h3>\n\n\n\n<p>Dieser Artikel hat alle JEPs vorgestellt, die in Java 27 ver\u00f6ffentlicht wurden \u2013 und zudem einige ausgew\u00e4hlte \u00c4nderungen aus den Release Notes. Die vollst\u00e4ndige Liste aller \u00c4nderungen findest du in den offiziellen <a href=\"https:\/\/jdk.java.net\/27\/release-notes\" target=\"_blank\" rel=\"noopener\">Java 27 Release Notes<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"fazit\">Fazit<\/h2>\n\n\n\n<p>In Java 27 gibt es keine gro\u00dfen neuen Sprachfeatures, aber dennoch einige nennenswerte \u00c4nderungen: <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.happycoders.eu\/de\/java\/compact-object-headers\/\">Compact Object Headers<\/a> sind standardm\u00e4\u00dfig aktiviert, was bei Anwendungen mit vielen kleinen Objekten bis zu 20 % Heap einsparen und den Durchsatz um bis zu 10 % erh\u00f6hen kann.  <\/li>\n\n\n\n<li>Der Java Flight Recorder kann vertrauliche Informationen schw\u00e4rzen, wodurch m\u00f6gliche Angriffsvektoren geschlossen wurden.<\/li>\n\n\n\n<li>TLS verwendet \u2013 sofern der Server das unterst\u00fctzt \u2013 automatisch quantensichere Verschl\u00fcsselung, wodurch sogenannte \u201e<a href=\"https:\/\/en.wikipedia.org\/wiki\/Harvest_now%2C_decrypt_later\" target=\"_blank\" rel=\"noopener\">Harvest now, decrypt later<\/a>\u201c-Angriffe unterbunden werden.<\/li>\n\n\n\n<li>G1 ist nun auch auf leistungsschw\u00e4cheren Maschinen (nur eine CPU oder weniger als 1.792 MB RAM) der Default-Garbage-Collector.<\/li>\n\n\n\n<li>Bei Lazy Constants wurden \u2013 wie auch schon in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/#lazy-constants-aenderungen-in-java-26\">Java 26<\/a> \u2013 weitere Low-Level-Methoden entfernt; zudem wurden der API <em>Lazy Sets<\/em> hinzugef\u00fcgt.<\/li>\n\n\n\n<li><code>StructuredTaskScope<\/code> hat nun einen weitere Typ-Parameter f\u00fcr den Exception-Typ; <code>join()<\/code> wirft \u2013 wenn nicht anders angegeben \u2013 eine <code>ExecutionException<\/code> (statt eine <code>FailedException<\/code>); der <code>awaitAll()<\/code>-Joiner wurde entfernt; <code>Joiner.onTimeout()<\/code> wurde durch <code>timeout()<\/code> ersetzt.<\/li>\n\n\n\n<li>Bei PEM Encodings of Cryptographic Objects wurde der <code>PEM<\/code>-Record zu einer Klasse, und einige andere Klassen und Methoden wurden umbenannt. <\/li>\n\n\n\n<li>Primitive Type Patterns und die Vector API wurden ohne \u00c4nderungen in die n\u00e4chste Preview- bzw. Incubator-Runde geschickt.<\/li>\n<\/ul>\n\n\n\n<p>Diverse sonstige \u00c4nderungen runden wie immer das Release ab. Das aktuelle Java-27-Early-Access-Release kannst du <a href=\"https:\/\/jdk.java.net\/27\/\" target=\"_blank\" rel=\"noopener\">hier<\/a> herunterladen.<\/p>\n\n\n\n<p>Welche der \u00c4nderungen findest du am spannendsten? Ich freue mich auf deine Meinung in den Kommentaren!<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neue Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>Alle neuen Java-27-Features verst\u00e4ndlich erkl\u00e4rt \u2013 mit Codebeispielen: Compact Object Headers per Default, G1 \u00fcberall, quantensicheres TLS, Lazy Sets und mehr.<\/p>\n","protected":false},"author":1,"featured_media":56108,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"Java 27 erkl\u00e4rt \u2013 mit Codebeispielen: Compact Object Headers per Default, G1 \u00fcberall, quantensicheres TLS, neue Preview-Features wie Lazy Sets.","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"64","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"java 27,java 27 features","_seopress_news_disabled":"","_seopress_video_disabled":"","_seopress_video":[],"_seopress_pro_schemas_manual":[],"_seopress_pro_rich_snippets_disable_all":"","_seopress_pro_rich_snippets_disable":[],"_seopress_pro_schemas":[],"_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"0","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":39648,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-56104","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java-versionen"],"uagb_featured_image_src":{"full":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2026\/06\/java-27-feature-image.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":0,"uagb_excerpt":"Alle neuen Java-27-Features verst\u00e4ndlich erkl\u00e4rt \u2013 mit Codebeispielen: Compact Object Headers per Default, G1 \u00fcberall, quantensicheres TLS, Lazy Sets und mehr.","public_identification_id":"b8de9b87808c49448c11eb1e90eb6639","private_identification_id":"453c4d2a8f90419a8f103ac801285c21","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/56104","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/comments?post=56104"}],"version-history":[{"count":65,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/56104\/revisions"}],"predecessor-version":[{"id":56172,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/56104\/revisions\/56172"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/56108"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=56104"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=56104"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=56104"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}