{"id":35614,"date":"2023-06-08T06:00:00","date_gmt":"2023-06-08T04:00:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=35614"},"modified":"2026-01-24T12:49:40","modified_gmt":"2026-01-24T11:49:40","slug":"java-21-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-21-features\/","title":{"rendered":"Java 21 Features (mit Beispielen)"},"content":{"rendered":"\n<p>Am 19. September 2023 wurde mit gro\u00dfen Launch-Events die Ver\u00f6ffentlichung von Java 21, der neuesten Long-Term-Support-Version (nach <a href=\"\/de\/java\/java-17-features\/\">Java 17<\/a>), gefeiert. Oracle wird f\u00fcr mindestens f\u00fcnf Jahre, also bis September 2028, kostenlose Upgrades zur Verf\u00fcgung stellen \u2013 und bis September 2031 einen erweiterten, kostenpflichtigen Support.<\/p>\n\n\n\n<p>Die Highlights von Java 21:<\/p>\n\n\n\n<ul class=\"wp-block-list hc-checked-list\">\n<li>Mit <a href=\"#Virtual_Threads_JEP_444\">Virtuellen Threads<\/a> wird eine der bedeutendsten Neuerungen der Java-Geschichte finalisiert.<\/li>\n\n\n\n<li>Ebenfalls finalisiert werden zwei neue Java-Sprachfeatures aus Project Amber: <a href=\"#Record_Patterns_JEP_440\">Record Patterns<\/a> und <a href=\"#Pattern_Matching_for_switch_JEP_441\">Pattern Matching for switch<\/a>.<\/li>\n\n\n\n<li>Ein neues, \u00e4u\u00dferst praktisches Interface, <a href=\"#Sequenced_Collections_JEP_431\">SequencedCollection<\/a>, erm\u00f6glicht den direkten Zugriff auf das erste und letzte Element einer geordneten Collection.<\/li>\n\n\n\n<li>Zwei lang ersehnte Features, die andere Sprachen seit langem bieten, gibt es nun endlich auch in Java (vorerst als Preview-Feature): <a href=\"#String_Templates_Preview_JEP_430\">String Templates<\/a> und <a href=\"#Unnamed_Patterns_and_Variables_Preview_JEP_443\">Unnamed Patterns and Variables<\/a>.<\/li>\n<\/ul>\n\n\n\n<p>Wie immer verwende ich ausschlie\u00dflich die englischen Bezeichnungen der JEPs.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"virtual-threads-jep-444\">Virtual Threads \u2013 JEP 444<\/h2>\n\n\n\n<p>Bei der Skalierung von Server-Anwendungen stellen Threads oft einen Engpass dar. Ihre Anzahl ist begrenzt, und sie m\u00fcssen h\u00e4ufig auf Ereignisse warten, wie beispielsweise die Antwort einer Datenbankabfrage oder eines Remote-Aufrufs, oder sie werden durch Locks blockiert.<\/p>\n\n\n\n<p>Bisherige L\u00f6sungsans\u00e4tze wie <code>CompletableFuture<\/code> oder reaktive Frameworks f\u00fchren zu extrem schwer les- und wartbaren Code.<\/p>\n\n\n\n<p>Mehrere Jahre lang wurde in <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/projects\/loom\/\" target=\"_blank\">Project Loom<\/a> an einer besseren L\u00f6sung gearbeitet. In <a href=\"\/de\/java\/java-19-features\/#Virtual_Threads_Preview_-_JEP_425\">Java 19<\/a> war es dann endlich so weit: Virtuelle Threads wurden erstmals als Preview-Feature vorgestellt.<\/p>\n\n\n\n<p>In Java 21 werden virtuelle Threads durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/444\" target=\"_blank\">JDK Enhancement Proposal 444<\/a> finalisiert und sind somit reif f\u00fcr den Einsatz in Produktion.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Was sind virtuelle Threads?<\/h4>\n\n\n\n<p>Im Gegensatz zu reaktivem Code erm\u00f6glichen virtuelle Threads die Programmierung im vertrauten, sequentiellen Thread-pro-Request-Stil.<\/p>\n\n\n\n<p>Sequentieller Code ist nicht nur einfacher zu schreiben und zu lesen, sondern auch leichter zu debuggen, da der Programmablauf in einem Debugger Schritt f\u00fcr Schritt nachverfolgt werden kann und Stacktraces den erwarteten Aufrufstack widerspiegeln. Jeder, der schon einmal versucht hat eine reaktive Anwendung zu debuggen, wird verstehen, was gemeint ist.<\/p>\n\n\n\n<p>Erm\u00f6glicht wird das dadurch, dass sich viele virtuelle Threads einen Plattform-Thread (so werden die herk\u00f6mmlichen, vom Betriebssystem bereitgestellten Threads genannt) teilen. Sobald ein virtueller Thread warten muss oder blockiert wird, wird der Plattform-Thread einen anderen virtuellen Thread ausf\u00fchren.<\/p>\n\n\n\n<p>Dadurch k\u00f6nnen wir mit wenigen Betriebssystem-Threads mehrere Millionen (!) virtuelle Threads ausf\u00fchren.<\/p>\n\n\n\n<p>Das Beste daran ist, dass wir den bestehenden Java-Code nicht einmal \u00e4ndern m\u00fcssen. Wir m\u00fcssen lediglich unserem Application Framework mitteilen, dass es nicht mehr Plattform-Threads, sondern virtuelle Threads einsetzen soll.<\/p>\n\n\n\n<p>Wie virtuelle Threads genau funktionieren, welche Einschr\u00e4nkungen sie haben und was hinter den Kulissen passiert, kannst du im <a href=\"https:\/\/www.happycoders.eu\/de\/java\/virtual-threads\/\">Hauptartikel \u00fcber virtuelle Threads<\/a> nachlesen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u00c4nderungen gegen\u00fcber der Preview-Version<\/h4>\n\n\n\n<p>In den Preview-Versionen war es m\u00f6glich, einen virtuellen Thread so zu konfigurieren, dass dieser keine <code>ThreadLocal<\/code>-Variablen haben kann (da die sehr teuer sein k\u00f6nnen, sollen virtuelle Threads stattdessen die in Java 21 als Preview enthaltenen <a href=\"#Scoped_Values_Preview_-_JEP_446\">Scoped Values<\/a> verwenden). Diese M\u00f6glichkeit wurde wieder entfernt, damit so viel existierender Code wie m\u00f6glich ohne \u00c4nderungen auch in virtuellen Threads laufen kann.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sequenced-collections-jep-431\">Sequenced Collections \u2013 JEP 431<\/h2>\n\n\n\n<p>Was ist der einfachste Weg, um auf das letzte Element einer Liste zuzugreifen? Sofern man keine zus\u00e4tzlichen Libraries oder Hilfsmethoden verwendet, ist es in Java \u2013 bisher \u2013 der folgende:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">var<\/span> last = list.get(list.size() - <span class=\"hljs-number\">1<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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>In Java 21 k\u00f6nnen wir dieses Unget\u00fcm endlich durch einen kurzen und pr\u00e4gnanten Aufruf ersetzen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">var<\/span> last = list.getLast();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><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>Vielleicht musstest du auch schon einmal auf das erste Element eines <code>LinkedHashSet<\/code> zugreifen? Das erforderte bisher den folgenden Umweg:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">var<\/span> first = linkedHashSet.iterator().next();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><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>In Java 21 geht auch das einfacher:<\/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\">var<\/span> first = linkedHashSet.getFirst();<\/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>Um auf das <em>letzte<\/em> Element eines <code>LinkedHashSet<\/code> zuzugreifen musste man sogar \u00fcber das komplette Set iterieren! Auch das geht jetzt ganz einfach mit <code>getLast()<\/code>.<\/p>\n\n\n\n<p>Steigen wir ein wenig in die Details ein...<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">SequencedCollection Interface<\/h4>\n\n\n\n<p>Um neue, einheitliche Methoden zum Zugriff auf die Elemente einer Collection mit stabiler Iterationsreihenfolge zu erm\u00f6glichen, wurde in Java 21 das Interface <code>SequencedCollection<\/code> eingef\u00fchrt. Dieses definiert unter anderem die zwei oben vorgestellten Methoden <code>getFirst()<\/code> und <code>getLast()<\/code> und wird von denjenigen Interfaces geerbt bzw. Klassen implementiert wird, deren Elemente die o. g. stabile Iterationsreihenfolge haben:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>List<\/code> (z. B. <code>ArrayList<\/code>, <code>LinkedList<\/code>)<\/li>\n\n\n\n<li><code>SortedSet<\/code> und dessen Erweiterung <code>NavigableSet<\/code> (z. B. <code>TreeSet<\/code>)<\/li>\n\n\n\n<li><code>LinkedHashSet<\/code><\/li>\n<\/ul>\n\n\n\n<p>Neben den oben genannten Methoden definiert <code>SequencedCollection&lt;E&gt;<\/code> noch folgende Methoden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>void addFirst(E)<\/code> \u2013 f\u00fcgt ein Element am Anfang der Collection ein<\/li>\n\n\n\n<li><code>void addLast(E)<\/code> \u2013 h\u00e4ngt ein Element an das Ende der Collection an<\/li>\n\n\n\n<li><code>E removeFirst()<\/code> \u2013 entfernt das erste Element und gibt es zur\u00fcck<\/li>\n\n\n\n<li><code>E removeLast()<\/code> \u2013 entfernt das letzte Element und gibt es zur\u00fcck<\/li>\n<\/ul>\n\n\n\n<p>Alle vier Methoden werfen bei unver\u00e4nderlichen Collections eine <code>UnsupportedOperationException<\/code>.<\/p>\n\n\n\n<p>Eine weitere Methode ist:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>SequencedCollection reversed();<\/code><\/li>\n<\/ul>\n\n\n\n<p>Diese liefert eine View auf die <code>Collection<\/code> in umgekehrter Reihenfolge. Diese kann verwendet werden, um r\u00fcckw\u00e4rts \u00fcber die <code>Collection<\/code> zu iterieren. \u201eView\u201d bedeutet, dass \u00c4nderungen an der urspr\u00fcnglichen <code>Collection<\/code> auch in der View sichtbar sind und umgekehrt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">SequencedSet Interface<\/h4>\n\n\n\n<p>Das neue Interface <code>SequencedSet<\/code> erbt von <code>Set<\/code> und <code>SequencedCollection<\/code>. Es bietet keine zus\u00e4tzlichen Methoden, \u00fcberschreibt allerdings die <code>reversed()<\/code>-Methode, um den R\u00fcckgabetyp <code>SequencedCollection<\/code> durch <code>SequencedSet<\/code> zu ersetzen.<\/p>\n\n\n\n<p>Dar\u00fcberhinaus haben <code>addFirst(E)<\/code> und <code>addLast(E)<\/code> im <code>SequencedSet<\/code> eine besondere Bedeutung: Wenn das hinzuzuf\u00fcgende Element bereits im Set enthalten ist, wird es an den Anfang bzw. an das Ende des Sets verschoben.<\/p>\n\n\n\n<p>Die folgende Grafik zeigt, wie <code>SequencedCollection<\/code> und <code>SequencedSet<\/code> in die bestehende Klassenhierarchie eingef\u00fcgt wurden (der \u00dcbersichtlich halber wird nur eine Auswahl\u00b9 an Klassen angezeigt):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"589\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-800x589.png\" alt=\"SequencedCollection und SequencedSet in der Java-21-Klassenhierarchie\" class=\"wp-image-35655\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-800x589.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-224x165.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-336x247.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-504x371.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-672x495.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-400x295.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-600x442.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-944x695.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21-1200x884.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedcollection-sequencedset-java-21.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\"><code>SequencedCollection<\/code> und <code>SequencedSet<\/code> in der Java-21-Klassenhierarchie<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"hc-footnote\">\u00b9 Die Auswahl beschr\u00e4nkt sich auf diejenigen Klassen, die im JDK-Quellcode mindestens 100 mal verwendet werden.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">SequencedMap Interface<\/h4>\n\n\n\n<p>In Java stellen Collections (z. B. Listen, Sets) und Maps (z. B. <code>HashMap<\/code>) zwei separate Klassenhierarchien dar. F\u00fcr geordnete Maps (also solche, deren Elemente eine definierte Reihenfolge haben) wird ebenfalls ein neues Interface, <code>SequencedMap<\/code>, bereitgestellt, das einfachen Zugriff auf das erste und letzte Element einer solchen Map bietet.<\/p>\n\n\n\n<p><code>SequencedMap<\/code> bietet analog zu <code>SequencedCollection<\/code> die folgende Methoden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Entry&lt;K, V&gt; firstEntry()<\/code> \u2013 gibt das erste Key-Value-Paar der Map zur\u00fcck<\/li>\n\n\n\n<li><code>Entry&lt;K, V&gt; lastEntry()<\/code> \u2013 gibt das letzte Key-Value-Paar der Map zur\u00fcck<\/li>\n\n\n\n<li><code>Entry&lt;K, V&gt; pollFirstEntry()<\/code> \u2013 entfernt das erste Key-Value-Paar und gibt es zur\u00fcck<\/li>\n\n\n\n<li><code>Entry&lt;K, V&gt; pollLastEntry()<\/code> \u2013 entfernt das letzte Key-Value-Paar und gibt es zur\u00fcck<\/li>\n\n\n\n<li><code>V putFirst(K, V)<\/code> \u2013 f\u00fcgt ein Key-Value-Paar am Anfang der Map ein<\/li>\n\n\n\n<li><code>V putLast(K, V)<\/code> \u2013 h\u00e4ngt ein Key-Value-Paar am Ende der Map an<\/li>\n\n\n\n<li><code>SequencedMap&lt;K, V&gt; reversed()<\/code> \u2013 liefert eine View auf die Map in umgekehrter Reihenfolge<\/li>\n<\/ul>\n\n\n\n<p>Sollte zu einem Key bereits ein Eintrag existieren, wird dieser von <code>putFirst()<\/code> und <code>putLast()<\/code> \u00fcberschrieben und an den Anfang bzw. ans Ende der Map verschoben.<\/p>\n\n\n\n<p>Dar\u00fcberhinaus gibt es drei weitere Methoden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>SequencedSet sequencedKeySet()<\/code> \u2013 liefert die Keys der Map<\/li>\n\n\n\n<li><code>SequencedCollection&lt;V&gt; sequencedValues()<\/code> \u2013 liefert die Values der Map<\/li>\n\n\n\n<li><code>SequencedSet&lt;Entry&lt;K,V&gt;&gt; sequencedEntrySet()<\/code> \u2013 liefert alle Eintr\u00e4ge der Map<\/li>\n<\/ul>\n\n\n\n<p>Hier siehst du, wie das neue Interface in die bestehende Klassenhierarchie eingef\u00fcgt wurde (dieses Mal mit allen implementierenden Klassen):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-half_400\"><img decoding=\"async\" width=\"400\" height=\"481\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21-400x481.png\" alt=\"SequencedMap in der Java-21-Klassenhierarchie\" class=\"wp-image-35660\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21-400x481.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21-224x269.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21-336x404.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21-504x606.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21-672x808.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21-600x722.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/sequencedmap-java-21.png 800w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><figcaption class=\"wp-element-caption\"><code>SequencedMap<\/code> in der Java-21-Klassenhierarchie<\/figcaption><\/figure>\n<\/div>\n\n\n<p><code>SequencedCollection<\/code>, <code>SequencedSet<\/code> und <code>SequencedMap<\/code> werden in <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/431\" target=\"_blank\">JDK Enhancement Proposal 431<\/a> definiert.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Neue Collections-Methoden<\/h4>\n\n\n\n<p>Die <code>Collections<\/code>-Utility-Klasse wurde um einige statische Hilfsmethoden, speziell f\u00fcr Sequenced Collections, erweitert:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>newSequencedSetFromMap(SequencedMap map)<\/code> \u2013 analog zu <code>Collections.setFromMap(\u2026)<\/code> liefert diese Methode ein <code>SequencedSet<\/code> mit den Eigenschaften der zugrunde liegenden Map.<\/li>\n\n\n\n<li><code>unmodifiableSequencedCollection(SequencedCollection c)<\/code> \u2013 gibt analog zu <code>Collections.unmodifiableCollection(\u2026)<\/code> eine unver\u00e4nderliche Sicht auf die zugrunde liegende <code>SequencedCollection<\/code> zur\u00fcck.\n<ul class=\"wp-block-list\">\n<li><em>Unver\u00e4nderlich<\/em> bedeutet, dass Aufrufe von \u00e4ndernden Methoden, wie z. B. <code>add(\u2026)<\/code> oder <code>remove(\u2026)<\/code> eine <code>UnsupportedOperationException<\/code> werfen. <\/li>\n\n\n\n<li><em>Sicht<\/em> bedeutet, dass \u00c4nderungen an der zugrunde liegenden Collection in der von <code>unmodifiableSequencedCollection(\u2026)<\/code> zur\u00fcckgegebenen Collection sichtbar sind.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><code>Collections.unmodifiableSequencedMap(SequencedMap m)<\/code> \u2013 gibt analog zu <code>Collections.unmodifiableMap(\u2026)<\/code> eine unver\u00e4nderliche Sicht auf die zugrunde liegende <code>SequencedMap<\/code> zur\u00fcck.<\/li>\n\n\n\n<li><code>Collections.unmodifiableSequencedSet(SequencedSet s)<\/code> \u2013 gibt analog zu <code>Collections.unmodifiableSet(\u2026)<\/code> eine unver\u00e4nderliche Sicht auf das zugrunde liegende <code>SequencedSet<\/code> zur\u00fcck.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"record-patterns-jep-440\">Record Patterns \u2013 JEP 440<\/h2>\n\n\n\n<p>\u201eRecord Patterns\u201d wurde erstmals in <a href=\"\/de\/java\/java-19-features\/#Record_Patterns_Preview_-_JEP_405\">Java 19<\/a> als Preview-Feature vorgestellt. Sie k\u00f6nnen in Kombination mit <em>Pattern Matching for instanceof<\/em> und <em>Pattern Matching for switch<\/em> verwendet werden, um ohne explizite Casts und ohne Verwendung von Zugriffsmethoden auf die Felder eines Records zuzugreifen.<\/p>\n\n\n\n<p>Das h\u00f6rt sich komplizierter an als es ist. Am besten erkl\u00e4re ich <em>Record Patterns<\/em> an einem Beispiel:<\/p>\n\n\n\n<p>Wir beginnen mit einem einfachen Record (falls du mit Records noch nicht vertraut bist, findest du hier eine <a href=\"\/de\/java\/java-records\/\">Einf\u00fchrung in Java-Records<\/a>).<\/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-function\"><span class=\"hljs-keyword\">public<\/span> record <span class=\"hljs-title\">Position<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y)<\/span> <\/span>{}<\/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>Nun nehmen wir an, wir haben ein beliebiges Objekt und wollen damit \u2013 abh\u00e4ngig von dessen Klasse \u2013 eine bestimmte Aktion durchf\u00fchren, z. B. etwas auf der Konsole ausgeben. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Record Patterns und Pattern Matching for instanceof<\/h4>\n\n\n\n<p>Das k\u00f6nnten wir mit dem in <a href=\"\/de\/java\/java-16-features\/#Pattern_Matching_for_instanceof\">Java 16<\/a> eingef\u00fchrten <em>Pattern Matching for instanceof<\/em> z. B. wie folgt machen:<\/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\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (o <span class=\"hljs-keyword\">instanceof<\/span> Position p) {\n    System.out.printf(<span class=\"hljs-string\">\"o is a position: %d\/%d%n\"<\/span>, p.x(), p.y());\n  } <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (o <span class=\"hljs-keyword\">instanceof<\/span> String s) {\n    System.out.printf(<span class=\"hljs-string\">\"o is a string: %s%n\"<\/span>, s);\n  } <span class=\"hljs-keyword\">else<\/span> {\n    System.out.printf(<span class=\"hljs-string\">\"o is something else: %s%n\"<\/span>, o);\n  }\n}<\/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>Anstatt auf das Pattern <code>Position p<\/code> k\u00f6nnen wir nun auch auf ein sogenanntes <em>Record Pattern<\/em> matchen \u2013 n\u00e4mlich <code>Position(int x, int y)<\/code> \u2013 und dann im nachfolgenden Code anstatt auf <code>p.x()<\/code> und <code>p.y()<\/code> direkt auf die Variablen <code>x<\/code> und <code>y<\/code> zugreifen:<\/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\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">o <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-title\">Position<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y)<\/span>) <\/span>{\n    System.out.printf(<span class=\"hljs-string\">\"o is a position: %d\/%d%n\"<\/span>, x, y);\n  } <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (o <span class=\"hljs-keyword\">instanceof<\/span> String s) {\n    System.out.printf(<span class=\"hljs-string\">\"o is a string: %s%n\"<\/span>, s);\n  } <span class=\"hljs-keyword\">else<\/span> {\n    System.out.printf(<span class=\"hljs-string\">\"o is something else: %s%n\"<\/span>, o);\n  }\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<h4 class=\"wp-block-heading\">Record Patterns und Pattern Matching for switch<\/h4>\n\n\n\n<p>Das erste Beispiel (ohne <em>Record Pattern<\/em>) k\u00f6nnen wir auch mit dem ebenfalls in Java 21 finalisierten <a href=\"#Pattern_Matching_for_switch_-_JEP_441\">Pattern Matching for switch<\/a> schreiben:<\/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\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (o) {\n    <span class=\"hljs-keyword\">case<\/span> Position p -&gt; System.out.printf(<span class=\"hljs-string\">\"o is a position: %d\/%d%n\"<\/span>, p.x(), p.y());\n    <span class=\"hljs-keyword\">case<\/span> String s   -&gt; System.out.printf(<span class=\"hljs-string\">\"o is a string: %s%n\"<\/span>, s);\n    <span class=\"hljs-keyword\">default<\/span>         -&gt; System.out.printf(<span class=\"hljs-string\">\"o is something else: %s%n\"<\/span>, o);\n  }\n}\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>Auch das Switch-Statement k\u00f6nnen wir mit einem Record Pattern kombinieren:<\/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-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (o) {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Position<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y)<\/span> -&gt; System.out.<span class=\"hljs-title\">printf<\/span><span class=\"hljs-params\">(<span class=\"hljs-string\">\"o is a position: %d\/%d%n\"<\/span>, x, y)<\/span><\/span>;\n    <span class=\"hljs-keyword\">case<\/span> String s               -&gt; System.out.printf(<span class=\"hljs-string\">\"o is a string: %s%n\"<\/span>, s);\n    <span class=\"hljs-keyword\">default<\/span>                     -&gt; System.out.printf(<span class=\"hljs-string\">\"o is something else: %s%n\"<\/span>, o);\n  }\n}\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\">Verschachtelte Record Patterns<\/h4>\n\n\n\n<p>Wir k\u00f6nnen nicht nur auf ein Record matchen, dessen Felder Objekte oder Primitive sind. Wir k\u00f6nnen ebenso auf ein Record matchen, dessen Felder ebenfalls Records sind.<\/p>\n\n\n\n<p>Als Beispiel nehmen wir den folgenden Record, <code>Path<\/code>, mit einer Start- und einer Endposition hinzu:<\/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-function\"><span class=\"hljs-keyword\">public<\/span> record <span class=\"hljs-title\">Path<\/span><span class=\"hljs-params\">(Position from, Position to)<\/span> <\/span>{}<\/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>Die <code>print()<\/code>-Methode aus den vorigen Beispielen soll nun auch einen <code>Path<\/code> ausgeben k\u00f6nnen \u2013 hier zun\u00e4chst die Implementierung <em>ohne<\/em> Record Pattern:<\/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-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (o) {\n    <span class=\"hljs-keyword\">case<\/span> Path p -&gt;\n            System.out.printf(<span class=\"hljs-string\">\"o is a path: %d\/%d -&gt; %d\/%d%n\"<\/span>, \n                    p.from().x(), p.from().y(), p.to().x(), p.to().y()); \n    <span class=\"hljs-comment\">\/\/ other cases<\/span>\n  }\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><em>Mit<\/em> einem Record Pattern k\u00f6nnten wir zum einen auf <code>Path(Position from, Position to)<\/code> matchen:<\/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\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (o) {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Path<\/span><span class=\"hljs-params\">(Position from, Position to)<\/span> -&gt;\n            System.out.<span class=\"hljs-title\">printf<\/span><span class=\"hljs-params\">(<span class=\"hljs-string\">\"o is a path: %d\/%d -&gt; %d\/%d%n\"<\/span>, \n                    from.x()<\/span>, from.<span class=\"hljs-title\">y<\/span><span class=\"hljs-params\">()<\/span>, to.<span class=\"hljs-title\">x<\/span><span class=\"hljs-params\">()<\/span>, to.<span class=\"hljs-title\">y<\/span><span class=\"hljs-params\">()<\/span>)<\/span>;\n    <span class=\"hljs-comment\">\/\/ other cases<\/span>\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>Wir k\u00f6nnen aber auch ein <em>verschachteltes<\/em> Record Pattern verwenden, und zwar wie folgt:<\/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\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (o) {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Path<\/span><span class=\"hljs-params\">(Position(<span class=\"hljs-keyword\">int<\/span> x1, <span class=\"hljs-keyword\">int<\/span> y1)<\/span>, <span class=\"hljs-title\">Position<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x2, <span class=\"hljs-keyword\">int<\/span> y2)<\/span>) -&gt;\n            System.out.<span class=\"hljs-title\">printf<\/span><span class=\"hljs-params\">(<span class=\"hljs-string\">\"o is a path: %d\/%d -&gt; %d\/%d%n\"<\/span>, x1, y1, x2, y2)<\/span><\/span>;\n    <span class=\"hljs-comment\">\/\/ other cases<\/span>\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>In den bisherigen Beispielen bringt die Schreibweise mit Record Patterns keinen allzu gro\u00dfen Vorteil. Ihre wahre St\u00e4rke k\u00f6nnen Record Patterns dann zeigen, wenn sie mit Records verwendet werden, deren Elemente verschiedene Typen haben k\u00f6nnen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Die wahre St\u00e4rke von Record Patterns<\/h4>\n\n\n\n<p>Wir \u00e4ndern unsere Records etwas ab. <code>Position<\/code> wird zu einem Interface, welches von <code>Position2D<\/code> und <code>Position3D<\/code> implementiert wird. Und <code>Path<\/code> wird so angepasst, dass beide Parameter vom gleichen Typ sein m\u00fcssen:<\/p>\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\">public<\/span> sealed <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">Position<\/span> <span class=\"hljs-title\">permits<\/span> <span class=\"hljs-title\">Position2D<\/span>, <span class=\"hljs-title\">Position3D<\/span> <\/span>{}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> record <span class=\"hljs-title\">Position2D<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y)<\/span> implements Position <\/span>{}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> record <span class=\"hljs-title\">Position3D<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y, <span class=\"hljs-keyword\">int<\/span> z)<\/span> implements Position <\/span>{}\n\n<span class=\"hljs-keyword\">public<\/span> record Path&lt;P extends Position&gt;(P from, P to) {}\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>Die <code>print()<\/code>-Methode \u00e4ndern wir so ab, dass sie f\u00fcr einen 3D-Pfad etwas anderes anzeigt als f\u00fcr einen 2D-Pfad. Das ist ziemlich einfach zu bewerkstelligen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (o) {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Path<\/span><span class=\"hljs-params\">(Position2D from, Position2D to)<\/span> -&gt;\n            System.out.<span class=\"hljs-title\">printf<\/span><span class=\"hljs-params\">(<span class=\"hljs-string\">\"o is a 2D path: %d\/%d -&gt; %d\/%d%n\"<\/span>,\n                    from.x()<\/span>, from.<span class=\"hljs-title\">y<\/span><span class=\"hljs-params\">()<\/span>, to.<span class=\"hljs-title\">x<\/span><span class=\"hljs-params\">()<\/span>, to.<span class=\"hljs-title\">y<\/span><span class=\"hljs-params\">()<\/span>)<\/span>;\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Path<\/span><span class=\"hljs-params\">(Position3D from, Position3D to)<\/span> -&gt;\n            System.out.<span class=\"hljs-title\">printf<\/span><span class=\"hljs-params\">(<span class=\"hljs-string\">\"o is a 3D path: %d\/%d\/%d -&gt; %d\/%d\/%d%n\"<\/span>,\n                    from.x()<\/span>, from.<span class=\"hljs-title\">y<\/span><span class=\"hljs-params\">()<\/span>, from.<span class=\"hljs-title\">z<\/span><span class=\"hljs-params\">()<\/span>, to.<span class=\"hljs-title\">x<\/span><span class=\"hljs-params\">()<\/span>, to.<span class=\"hljs-title\">y<\/span><span class=\"hljs-params\">()<\/span>, to.<span class=\"hljs-title\">z<\/span><span class=\"hljs-params\">()<\/span>)<\/span>;\n    <span class=\"hljs-comment\">\/\/ other cases<\/span>\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><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>So einfach war es allerdings nur, da wir mit der Variante <em>mit<\/em> Record Patterns begonnen haben!<\/p>\n\n\n\n<p><em>Ohne<\/em> Record Patterns m\u00fcssten wir folgenden Code schreiben:<\/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\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">print<\/span><span class=\"hljs-params\">(Object o)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (o) {\n    <span class=\"hljs-keyword\">case<\/span> Path p when p.from() <span class=\"hljs-keyword\">instanceof<\/span> Position2D from \n                  &amp;&amp; p.to() <span class=\"hljs-keyword\">instanceof<\/span> Position2D to -&gt;\n            System.out.printf(<span class=\"hljs-string\">\"o is a 2D path: %d\/%d -&gt; %d\/%d%n\"<\/span>,\n                    from.x(), from.y(), to.x(), to.y());\n    <span class=\"hljs-keyword\">case<\/span> Path p when p.from() <span class=\"hljs-keyword\">instanceof<\/span> Position3D from \n                  &amp;&amp; p.to() <span class=\"hljs-keyword\">instanceof<\/span> Position3D to -&gt;\n            System.out.printf(<span class=\"hljs-string\">\"o is a 3D path: %d\/%d\/%d -&gt; %d\/%d\/%d%n\"<\/span>,\n                    from.x(), from.y(), from.z(), to.x(), to.y(), to.z());\n    <span class=\"hljs-comment\">\/\/ other cases<\/span>\n  }\n}<\/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>Dieses Mal ist die Variante <em>mit<\/em> Record Patterns deutlich pr\u00e4gnanter! Und je tiefer die Verschachtelung, desto gr\u00f6\u00dfer der Vorteil, der sich durch Record Patterns ergibt.<\/p>\n\n\n\n<p>Record Patterns wurden mit <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/440\" target=\"_blank\">JDK Enhancement Proposal 440<\/a> finalisiert \u2013 mit einer \u00c4nderung gegen\u00fcber der letzten Preview-Version:<\/p>\n\n\n\n<p>In <a href=\"\/de\/java\/java-20-features\/#Record_Patterns_Second_Preview_-_JEP_432\">Java 20<\/a> wurde die M\u00f6glichkeit eingef\u00fchrt, Record Patterns auch in for-Schleifen zu verwenden, so wie in folgendem Beispiel:<\/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\">List&lt;Position&gt; positions = ...\n\n<span class=\"hljs-keyword\">for<\/span> (Position(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y) : positions) {\n  System.out.printf(<span class=\"hljs-string\">\"(%d, %d)%n\"<\/span>, x, y);\n}<\/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>Diese Option wurde in der finalen Version des Features gestrichen, mit der Aussicht, sie in einer zuk\u00fcnftigen Java-Version erneut einzuf\u00fchren.<\/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=\"pattern-matching-for-switch-jep-441\">Pattern Matching for switch \u2013 JEP 441<\/h2>\n\n\n\n<p>\u201ePattern Matching for switch\u201d wurde erstmals in <a href=\"\/de\/java\/java-17-features\/#Pattern_Matching_for_switch_Preview\">Java 17<\/a> als Preview-Feature vorgestellt und erm\u00f6glicht in Kombination mit <a href=\"#Record_Patterns_-_JEP_440\">Record Patterns<\/a>, Switch-Statements (und -Ausdr\u00fccke) \u00fcber ein beliebiges Objekt zu formulieren. Hier ein Beispiel:<\/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\">Object obj = getObject();\n\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\">5<\/span> -&gt; System.out.println(s.toUpperCase());\n  <span class=\"hljs-keyword\">case<\/span> String s                     -&gt; System.out.println(s.toLowerCase());\n  <span class=\"hljs-keyword\">case<\/span> Integer i                    -&gt; System.out.println(i * i);\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Position<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y)<\/span>       -&gt; System.out.<span class=\"hljs-title\">println<\/span><span class=\"hljs-params\">(x + <span class=\"hljs-string\">\"\/\"<\/span> + y)<\/span><\/span>;\n  <span class=\"hljs-keyword\">default<\/span>                           -&gt; {}\n}<\/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<p>Ohne <em>Pattern Matching for switch<\/em> m\u00fcssten wir stattdessen folgenden, weniger ausdrucksstarken Code schreiben (dank des in <a href=\"\/de\/java\/java-16-features\/#Pattern_Matching_for_instanceof\">Java 16<\/a> eingef\u00fchrten <em>Pattern Matching for instanceof<\/em> ist er ohne explizite Cast dennoch einigerma\u00dfen gut lesbar):<\/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\">Object obj = getObject();\n\n<span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s &amp;&amp; s.length() &gt; <span class=\"hljs-number\">5<\/span>)  System.out.println(s.toUpperCase());\n<span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s)               System.out.println(s.toLowerCase());\n<span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer i)              System.out.println(i * i);\n<span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">obj <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-title\">Position<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y)<\/span>) System.out.<span class=\"hljs-title\">println<\/span><span class=\"hljs-params\">(x + <span class=\"hljs-string\">\"\/\"<\/span> + y)<\/span><\/span>;<\/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>Dar\u00fcber hinaus f\u00fchrt der Compiler bei <em>Pattern Matching for switch<\/em> eine Vollst\u00e4ndigkeitsanalyse (englisch: \u201eanalysis of exhaustiveness\u201d) durch, d. h. das Switch-Statement oder der Switch-Ausdruck muss alle m\u00f6glichen F\u00e4lle abdecken \u2013 oder einen <code>default<\/code>-Branch enthalten. Da die <code>Object<\/code>-Klasse im Beispiel oben beliebig erweiterbar ist, ist ein <code>default<\/code>-Branch zwingend erforderlich.<\/p>\n\n\n\n<p>Nicht n\u00f6tig ist ein <code>default<\/code>-Branch hingegen, wenn bei einer versiegelten Klassenhierarchie alle M\u00f6glichkeiten abgedeckt sind, wie in folgendem Beispiel:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> sealed <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">Shape<\/span> <span class=\"hljs-title\">permits<\/span> <span class=\"hljs-title\">Rectangle<\/span>, <span class=\"hljs-title\">Circle<\/span> <\/span>{}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> record <span class=\"hljs-title\">Rectangle<\/span><span class=\"hljs-params\">(Position topLeft, Position bottomRight)<\/span> implements Shape <\/span>{}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> record <span class=\"hljs-title\">Circle<\/span><span class=\"hljs-params\">(Position center, <span class=\"hljs-keyword\">int<\/span> radius)<\/span> implements Shape <\/span>{}\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ShapeDebugger<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">debug<\/span><span class=\"hljs-params\">(Shape shape)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">switch<\/span> (shape) {\n      <span class=\"hljs-keyword\">case<\/span> Rectangle r -&gt; System.out.printf(\n        <span class=\"hljs-string\">\"Rectangle: top left = %s; bottom right = %s%n\"<\/span>, r.topLeft(), r.bottomRight());\n\n      <span class=\"hljs-keyword\">case<\/span> Circle c -&gt; System.out.printf(\n        <span class=\"hljs-string\">\"Circle: center = %s; radius = %s%n\"<\/span>, c.center(), c.radius());\n    }\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><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>Da durch die Versiegelung sichergestellt ist, dass es nur zwei <code>Shape<\/code>-Implementierungen \u2013 n\u00e4mlich <code>Rectangle<\/code> und <code>Circle<\/code> \u2013 gibt, w\u00e4re hier ein <code>default<\/code>-Zweig \u00fcberfl\u00fcssig (aber nicht verboten, s. u.).<\/p>\n\n\n\n<p>W\u00fcrden wir irgendwann <code>Shape<\/code> erweitern, z. B. um einen dritten Record <code>Oval<\/code>, dann w\u00fcrde der Compiler den Switch-Ausdruck als unvollst\u00e4ndig erkennen und dies mit der Fehlermeldung <em>'switch' statement does not cover all possible input values<\/em> quittieren:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"238\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-800x238.png\" alt=\"Java 21 - Pattern Matching for switch - 'switch' statement does not cover all possible input values\" class=\"wp-image-33985\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-800x238.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-224x67.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-336x100.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-504x150.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-672x200.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-400x119.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-600x179.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-944x281.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch-1200x357.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-jep-433-exhaustive-switch.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n<\/div>\n\n\n<p>Auf diese Weise k\u00f6nnen wir im Voraus sicherstellen, dass wir bei einer Erweiterung des Interfaces auch alle Switch-Ausdr\u00fccke anpassen m\u00fcssen. Alternativ k\u00f6nnten wir vorab einen <code>default<\/code>-Zweig einbauen. Dann w\u00fcrde das switch-Statement weiterhin kompilieren und den <code>default<\/code>-Branch f\u00fcr <code>Oval<\/code> ausf\u00fchren.<\/p>\n\n\n\n<p>Mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/441\" target=\"_blank\">JDK Enhancement Proposal 441<\/a> wurde <em>Pattern Matching for switch<\/em> mit zwei \u00c4nderungen gegen\u00fcber der letzten Preview-Version finalisiert:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u201eParenthesized Patterns\u201d wurden entfernt<\/h4>\n\n\n\n<p>Bis Java 20 war es noch m\u00f6glich, Patterns in Klammern zu setzen, z. B. so:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Object obj = getObject();\n\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\">5<\/span> -&gt; System.out.println(s.toUpperCase());\n  <span class=\"hljs-keyword\">case<\/span> (String s)                     -&gt; System.out.println(s.toLowerCase());\n  <span class=\"hljs-keyword\">case<\/span> (Integer i)                    -&gt; System.out.println(i * i);\n  <span class=\"hljs-keyword\">case<\/span> (Position(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y))       -&gt; System.out.println(x + <span class=\"hljs-string\">\"\/\"<\/span> + y);\n  <span class=\"hljs-keyword\">default<\/span>                             -&gt; {}\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><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>Da die Klammern keinen Zweck erf\u00fcllten, wurde diese Option in der finalen Version von \u201ePattern Matching for switch\u201d entfernt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Qualifizierte Enum-Konstanten<\/h4>\n\n\n\n<p>Ein Switch-Ausdruck \u00fcber Enum-Konstanten lie\u00df sich bisher ausschlie\u00dflich mit einem \u201eGuarded Pattern\u201d \u2013 also einem Pattern kombiniert mit <code>when<\/code> \u2013 implementieren.<\/p>\n\n\n\n<p>Was das bedeutet, zeige ich dir an einem Beispiel. Hier zun\u00e4chst zwei Enums, die ein versiegeltes Interface implementieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> sealed <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">Direction<\/span> <span class=\"hljs-title\">permits<\/span> <span class=\"hljs-title\">CompassDirection<\/span>, <span class=\"hljs-title\">VerticalDirection<\/span> <\/span>{}\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">enum<\/span> CompassDirection implements Direction { NORTH, SOUTH, EAST, WEST }\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">enum<\/span> VerticalDirection implements Direction { UP, DOWN }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><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 switch \u00fcber alle m\u00f6glichen Richtungen musste bis Java 20 wie folgt implementiert werden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">flyJava20<\/span><span class=\"hljs-params\">(Direction direction)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (direction) {\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection  d when d == CompassDirection.NORTH -&gt; System.out.println(<span class=\"hljs-string\">\"Flying north\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection  d when d == CompassDirection.SOUTH -&gt; System.out.println(<span class=\"hljs-string\">\"Flying south\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection  d when d == CompassDirection.EAST  -&gt; System.out.println(<span class=\"hljs-string\">\"Flying east\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection  d when d == CompassDirection.WEST  -&gt; System.out.println(<span class=\"hljs-string\">\"Flying west\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> VerticalDirection d when d == VerticalDirection.UP   -&gt; System.out.println(<span class=\"hljs-string\">\"Gaining altitude\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> VerticalDirection d when d == VerticalDirection.DOWN -&gt; System.out.println(<span class=\"hljs-string\">\"Losing altitude\"<\/span>);\n    <span class=\"hljs-keyword\">default<\/span> -&gt; <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> IllegalArgumentException(<span class=\"hljs-string\">\"Unknown direction: \"<\/span> + direction);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><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>Bei dieser Schreibweise griff auch nicht die Vollst\u00e4ndigkeitsanalyse, d. h. obwohl wir alle m\u00f6glichen F\u00e4lle implementiert haben, ist dennoch ein <code>default<\/code>-Zweig notwendig. Andernfalls kommt es zu einem Compiler-Fehler.<\/p>\n\n\n\n<p>In Java 21 k\u00f6nnen wir dieselbe Logik jetzt deutlich pr\u00e4gnanter formulieren, indem wir direkt die qualifizierten Enum-Konstanten angeben (\"qualifiziert\" hei\u00dft: inklusive Klassenname):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">flyJava21<\/span><span class=\"hljs-params\">(Direction direction)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">switch<\/span> (direction) {\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection.NORTH -&gt; System.out.println(<span class=\"hljs-string\">\"Flying north\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection.SOUTH -&gt; System.out.println(<span class=\"hljs-string\">\"Flying south\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection.EAST  -&gt; System.out.println(<span class=\"hljs-string\">\"Flying east\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> CompassDirection.WEST  -&gt; System.out.println(<span class=\"hljs-string\">\"Flying west\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> VerticalDirection.UP   -&gt; System.out.println(<span class=\"hljs-string\">\"Gaining altitude\"<\/span>);\n    <span class=\"hljs-keyword\">case<\/span> VerticalDirection.DOWN -&gt; System.out.println(<span class=\"hljs-string\">\"Losing altitude\"<\/span>);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><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>Jetzt erkennt der Compiler auch, dass alle F\u00e4lle abgedeckt sind und fordert keinen <code>default<\/code>-Zweig mehr.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"neue-methoden-in-string-stringbuilder-stringbuffer-character-und-math\">Neue Methoden in String, StringBuilder, StringBuffer, Character und Math<\/h2>\n\n\n\n<p>Nicht alle \u00c4nderungen findet man in den JEPs oder Release Notes. So findet man z. B. einige neue Methoden in <code>String<\/code>, <code>StringBuilder<\/code>, <code>StringBuffer<\/code>, <code>Character<\/code> und <code>Math<\/code> nur in der API-Dokumentation. Praktischerweise gibt es den <a rel=\"noopener\" href=\"https:\/\/javaalmanac.io\/\" target=\"_blank\">Java Version Almanac<\/a>, mit dem man verschiedene API-Versionen komfortabel vergleichen kann.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"neue-string-methoden\">Neue String-Methoden<\/h3>\n\n\n\n<p>Die <code>String<\/code>-Klasse wurde um folgende Methoden erweitert:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>String.indexOf(String str, int beginIndex, int endIndex)<\/code> \u2013 sucht den angegebenen Substring in einem Teilbereich des Strings.<\/li>\n\n\n\n<li><code>String.indexOf(char ch, int beginIndex, int endIndex)<\/code> \u2013 sucht das angegebenen Zeichen in einem Teilbereich des Strings.<\/li>\n\n\n\n<li><code>String.splitWithDelimiters(String regex, int limit)<\/code> \u2013 teilt den String an Teilzeichenfolgen, auf die der regul\u00e4re Ausdruck passt, und gibt ein Array aller Teile und teilenden Zeichenfolgen zur\u00fcck. Es wird dabei maximal <code>limit-1<\/code> mal geteilt, d. h. das letzte Element des Arrays kann ggf. weiter teilbar sein kann.<\/li>\n<\/ul>\n\n\n\n<p>Hier ist ein Beispiel f\u00fcr <code>splitWithDelimiters(\u2026)<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">String string = <span class=\"hljs-string\">\"the red brown fox jumps over the lazy dog\"<\/span>;\nString&#091;] parts = string.splitWithDelimiters(<span class=\"hljs-string\">\" \"<\/span>, <span class=\"hljs-number\">5<\/span>);\nSystem.out.println(Arrays.stream(parts).collect(Collectors.joining(<span class=\"hljs-string\">\"', '\"<\/span>, <span class=\"hljs-string\">\"'\"<\/span>, <span class=\"hljs-string\">\"'\"<\/span>)));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><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>Diese Codezeilen geben folgendes aus:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">'the', ' ', 'red', ' ', 'brown', ' ', 'fox', ' ', 'jumps over the lazy dog'\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><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<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"neue-stringbuilder-und-stringbuffer-methoden\">Neue StringBuilder- und StringBuffer-Methoden<\/h3>\n\n\n\n<p>Sowohl <code>StringBuilder<\/code> als auch <code>StringBuffer<\/code> wurden um die folgenden zwei Methoden erweitert:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>repeat(CharSequence cs, int count)<\/code> \u2013 h\u00e4ngt an den <code>StringBuilder<\/code> oder <code>StringBuffer<\/code> die Zeichenkette <code>cs<\/code> an \u2013 und zwar <code>count<\/code> mal.<\/li>\n\n\n\n<li><code>repeat(int codePoint, int count)<\/code> \u2013 h\u00e4ngt an den <code>StringBuilder<\/code> oder <code>StringBuffer<\/code> den angegebenen Unicode-Codepoint an \u2013 und zwar <code>count<\/code> mal. Als codePoint kann auch eine Variable oder Konstante vom Typ <code>char<\/code> \u00fcbergeben werden.<\/li>\n<\/ul>\n\n\n\n<p>Hier ein Beispiel, das <code>repeat(\u2026)<\/code> einmal mit einer Zeichenkette aufruft, einmal mit einem Codepoint und einmal mit einem Character:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">StringBuilder sb = <span class=\"hljs-keyword\">new<\/span> StringBuilder();\nsb.repeat(<span class=\"hljs-string\">\"Hello \"<\/span>, <span class=\"hljs-number\">2<\/span>);\nsb.repeat(<span class=\"hljs-number\">0x1f600<\/span>, <span class=\"hljs-number\">5<\/span>);\nsb.repeat(<span class=\"hljs-string\">'!'<\/span>, <span class=\"hljs-number\">3<\/span>);\nSystem.out.println(sb);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><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>Dieser Code gibt Folgendes aus:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full_800\"><img decoding=\"async\" width=\"800\" height=\"56\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-800x56.png\" alt=\"Ausgabe mit Smileys\" class=\"wp-image-37104\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-800x56.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-224x16.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-336x24.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-504x35.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-672x47.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-400x28.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-600x42.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-944x66.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys-1200x84.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/08\/output-with-smileys.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"neue-character-methoden\">Neue Character-Methoden<\/h3>\n\n\n\n<p>Wo wir schon bei Emojis sind... folgende neue Methoden bietet die <code>Character<\/code>-Klasse:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>isEmoji(int)<\/code><\/li>\n\n\n\n<li><code>isEmojiComponent(int)<\/code><\/li>\n\n\n\n<li><code>isEmojiModifier(int)<\/code><\/li>\n\n\n\n<li><code>isEmojiModifierBase(int)<\/code><\/li>\n\n\n\n<li><code>isEmojiPresentation(int)<\/code><\/li>\n\n\n\n<li><code>isExtendedPictographic(int)<\/code><\/li>\n<\/ul>\n\n\n\n<p>Diese Methoden pr\u00fcfen, ob der \u00fcbergebene Unicode-Codepoint f\u00fcr ein Emoji oder eine Variante davon steht. Was diese Varianten genau bedeuten, kannst du in <a rel=\"noopener\" href=\"https:\/\/unicode.org\/reports\/tr51\/#Emoji_Properties_and_Data_Files\" target=\"_blank\">Anhang A der Unicode-Emoji-Spezifikation<\/a> nachlesen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"neue-math-methoden\">Neue Math-Methoden<\/h3>\n\n\n\n<p>Wie oft schon haben wir folgendes St\u00fcck Code geschrieben, um sicherzustellen, dass eine Zahl in einem vorgegebenen Wertebereich liegt, oder andernfalls hineingeschoben wird:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">if<\/span> (value &lt; min) {\n  value = min;\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (value &gt; max) {\n  value = max;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><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>Ab sofort k\u00f6nnen wir daf\u00fcr die <code>Math.clamp(<code>\u2026<\/code>)<\/code>-Methode verwenden, die es in folgenden vier Varianten gibt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>int clamp(long value, int min, int max)<\/code><\/li>\n\n\n\n<li><code>long clamp(long value, long min, long max)<\/code><\/li>\n\n\n\n<li><code>double clamp(double value, double min, double max)<\/code><\/li>\n\n\n\n<li><code>float clamp(float value, float min, float max)<\/code><\/li>\n<\/ul>\n\n\n\n<p>Diese Methoden pr\u00fcfen, ob <code>value<\/code> im Bereich <code>min<\/code> bis <code>max<\/code> liegt. Ist <code>value<\/code> kleiner als <code>min<\/code>, wird <code>min<\/code> zur\u00fcckgegebenen; ist <code>value<\/code> gr\u00f6\u00dfer als <code>max<\/code>, wird <code>max<\/code> zur\u00fcckgegeben.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"preview-und-incubator-features\">Preview- und Incubator-Features<\/h2>\n\n\n\n<p>Auch wenn Java 21 eine Long-Term-Support-Version ist, enth\u00e4lt sie neue sowie wiedervorgelegte Preview-Features. Preview-Features m\u00fcssen explizit mit der VM-Option <code>--enable-preview<\/code> aktiviert werden und werden in der Regel in folgenden Java-Versionen noch leicht \u00fcberarbeitet.<\/p>\n\n\n\n<p>Du kannst dich in den folgenden Abschnitten auf ein paar \u00e4u\u00dferst spannende neue Features freuen!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"string-templates-preview-jep-430\">String Templates (Preview) \u2013 JEP 430<\/h3>\n\n\n\n<div class=\"wp-block-uagb-info-box uagb-block-af9d0506 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top hc-infobox\"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\"><strong>Breaking News: <\/strong>Am 05.04.2024 hat Gavin Bierman <a href=\"https:\/\/mail.openjdk.org\/pipermail\/amber-spec-experts\/2024-April\/004106.html\" target=\"_blank\" rel=\"noopener\">bekanntgegeben, dass String Templates in der hier beschriebenen Form <em>nicht<\/em> ver\u00f6ffentlicht werden<\/a>. Es besteht Einigkeit dar\u00fcber, dass das Design ge\u00e4ndert werden soll, es besteht allerdings kein Konsens dar\u00fcber, <em>wie<\/em> es ge\u00e4ndert werden soll. Die Sprachentwickler wollen sich nun Zeit nehmen, das Design zu \u00fcberarbeiten. String Templates werden daher in <a href=\"\/de\/java\/java-23-features\/\">Java 23<\/a> nicht weiter enthalten sein, auch nicht mit <code>--enable-preview<\/code>.<\/p><\/div><\/div>\n\n\n\n<p>String Templates bieten eine dynamische M\u00f6glichkeit, Strings zu generieren, indem zur Laufzeit Platzhalter durch Variablenwerte und berechnete Ergebnisse ersetzt werden. Dieser als String-Interpolation bezeichnete Prozess, erm\u00f6glicht es, komplexe Strings effizient zusammenzustellen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">int<\/span> a = ...;\n<span class=\"hljs-keyword\">int<\/span> b = ...;\n\nString result = STR.<span class=\"hljs-string\">\"\\{a} times \\{b} = \\{Math.multiplyExact(a, b)}\"<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><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>W\u00e1hrend der Ausf\u00fchrung folgende Ersetzungen durchgef\u00fchrt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>\\{a}<\/code> wird dynamisch durch den aktuellen Wert von <code>a<\/code> ersetzt.<\/li>\n\n\n\n<li><code>\\{b}<\/code> wird durch den Wert von <code>b<\/code> ersetzt.<\/li>\n\n\n\n<li><code>\\{Math.multiplyExact(a, b)}<\/code> wird durch das Ergebnis des Methodenaufrufs <code>Math.multiplyExact(a, b)<\/code> ersetzt.<\/li>\n<\/ul>\n\n\n\n<p>String Templates wurden in Java 21 durch <a href=\"https:\/\/openjdk.org\/jeps\/430\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 430<\/a> als Preview-Feature eingef\u00fchrt. Eine ausf\u00fchrlichere Beschreibung findest du im <a href=\"\/de\/java\/string-templates\/\">Hauptartikel \u00fcber String Templates<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"unnamed-patterns-and-variables-preview-jep-443\">Unnamed Patterns and Variables (Preview) \u2013 JEP 443<\/h3>\n\n\n\n<p>H\u00e4ufig m\u00fcssen wir Variablen deklarieren, die letztendlich ungenutzt bleiben. Typische Beispiele hierf\u00fcr sind Exceptions, Lambda-Parameter und Pattern-Variablen.<\/p>\n\n\n\n<p>Betrachten wir ein Beispiel, in dem die Exception-Variable <code>e<\/code> ungenutzt bleibt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> {\n  <span class=\"hljs-keyword\">int<\/span> number = Integer.parseInt(string);\n} <span class=\"hljs-keyword\">catch<\/span> (NumberFormatException e) {\n  System.err.println(<span class=\"hljs-string\">\"Not a number\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><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>In diesem Fall bleibt der Lambda-Parameter <code>k<\/code> ungenutzt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">map.computeIfAbsent(key, k -&gt; <span class=\"hljs-keyword\">new<\/span> ArrayList&lt;&gt;()).add(value);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><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>Und in diesem Record-Pattern bleibt die Pattern-Variable <code>position2<\/code> ungenutzt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">object <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-title\">Path<\/span><span class=\"hljs-params\">(Position(<span class=\"hljs-keyword\">int<\/span> x1, <span class=\"hljs-keyword\">int<\/span> y1)<\/span>, Position position2)) <\/span>{\n  System.out.printf(<span class=\"hljs-string\">\"object is a path starting at x = %d, y = %d%n\"<\/span>, x1, y1));\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><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>In Java 22 bieten unbenannte Variablen und Patterns eine elegantere L\u00f6sung, indem sie es erm\u00f6glichen, die Namen von ungenutzten Variablen oder sogar das gesamte Pattern durch einen Unterstrich (_) zu ersetzen:<\/p>\n\n\n\n<p>Anstatt der Exception-Variable <code>e<\/code> k\u00f6nnen wir _ verwenden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> {\n  <span class=\"hljs-keyword\">int<\/span> number = Integer.parseInt(string);\n} <span class=\"hljs-keyword\">catch<\/span> (NumberFormatException _) {\n  System.err.println(<span class=\"hljs-string\">\"Not a number\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><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>Auch statt des Lambda-Parameters <code>k<\/code> verwenden wir _:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">map.computeIfAbsent(key, _ -&gt; <span class=\"hljs-keyword\">new<\/span> ArrayList&lt;&gt;()).add(value);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-35\"><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>Und das vollst\u00e4ndige Teil-Pattern <code>Position position2<\/code> kann ebenfalls durch _ ersetzt werden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">object <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-title\">Path<\/span><span class=\"hljs-params\">(Position(<span class=\"hljs-keyword\">int<\/span> x1, <span class=\"hljs-keyword\">int<\/span> y1)<\/span>, _)) <\/span>{\n  System.out.printf(<span class=\"hljs-string\">\"object is a path starting at x = %d, y = %d%n\"<\/span>, x1, y1));\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><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>Unnamed Patterns and Variables werden in&nbsp;<a href=\"https:\/\/openjdk.org\/jeps\/443\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 443<\/a>&nbsp;definiert. Weitere Details und eine tiefergehende Betrachtung dieses Features findest du im <a href=\"\/de\/java\/unbenannte-variablen-und-patterns\/\">Hauptartikel \u00fcber unbenannte Variablen und Patterns<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"unnamed-classes-and-instance-main-methods-preview-jep-445\">Unnamed Classes and Instance Main Methods (Preview) \u2013 JEP 445<\/h3>\n\n\n\n<p>Wenn Programmieranf\u00e4nger ihr erstes Java-Programm schreiben, sieht das in der Regel so aus:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HelloWorld<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n    System.out.println(<span class=\"hljs-string\">\"Hello world!\"<\/span>);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><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>Und das auch nur, wenn die Klasse im \u201eunbenannten Paket\u201d liegt. Ansonsten kommt auch noch eine <code>package<\/code>-Deklaration hinzu.<\/p>\n\n\n\n<p>Erfahrene Java-Entwickler erkennen die Elemente dieses Programms auf den ersten Blick. Doch Anf\u00e4nger werden \u00fcberw\u00e4ltigt von Visibility-Modifiern, komplexen Konzepten wie Klassen und statischen Methoden, unbenutzten Methoden-Argumenten und einem \u201eSystem.out\u201d.<\/p>\n\n\n\n<p>W\u00e4re es nicht sch\u00f6n, wenn man das meiste davon streichen k\u00f6nnte? Zum Beispiel so:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"1600\" height=\"304\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods.png\" alt=\"Java 21 - Unnamed Classes and Instance Main Methods\" class=\"wp-image-35734\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods.png 1600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-224x43.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-336x64.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-504x96.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-672x128.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-400x76.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-600x114.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-800x152.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-944x179.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java21-unnamed-classes-and-instance-main-methods-1200x228.png 1200w\" sizes=\"(max-width: 1600px) 100vw, 1600px\" \/><\/figure>\n\n\n\n<p>Genau das ist in Java 21 dank <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/445\" target=\"_blank\">JDK Enhancement Proposal 445<\/a> jetzt m\u00f6glich! Der folgende Code ist ab sofort ein g\u00fcltiges, vollst\u00e4ndiges Java-Programm:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n  System.out.println(<span class=\"hljs-string\">\"Hello world!\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><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>Da sich das Feature noch im Preview-Stadium befindet, musst du den Code wie folgt kompilieren und starten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-39\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ javac --enable-preview --source 21 HelloWorld.java\n$ java --enable-preview HelloWorld\nHello world!<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><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>Alternativ kannst du das Programm auch ohne explizites Kompilieren starten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java --enable-preview --source 21 HelloWorld.java\nHello world!<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-40\"><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>Den neuesten Stand dieses Features findest du im Abschnitt <a href=\"https:\/\/www.happycoders.eu\/de\/java\/main-methode\/#compact-source-files-and-instance-main-methods\">Compact Source Files and Instance Main Methods<\/a> (so wird das Feature ab <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-25-features\/\">Java 25<\/a> hei\u00dfen) des Artikels \u00fcber die Java-<em>main<\/em>-Methode.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Die \u201eunbenannte Klasse\u201d<\/h4>\n\n\n\n<div class=\"wp-block-uagb-info-box uagb-block-d21d8136 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top hc-infobox\"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\">In <a href=\"\/de\/java\/java-22-features\/#Implicitly_Declared_Classes_and_Instance_Main_Methods_Second_Preview_JEP_463\">Java 22<\/a> wurde das Konzept der \u201eunbenannten Klasse\u201d umgewandelt in eine \u201eimplizit deklarierte Klasse\u201d.<\/p><\/div><\/div>\n\n\n\n<p>Die <code>main()<\/code>-Methode liegt \u00fcbrigens nach wie vor in einer Klasse: der sogenannten \u201eunbenannten Klasse\u201d. Das ist kein g\u00e4nzlich neues Konzept. So gab es bisher schon das \u201eunbenannte Paket\u201d (eine Klasse ohne <code>package<\/code>-Deklaration) und das \u201eunbenannte Modul\u201d (ein Java-Quellcodeverzeichnis ohne \u201emodule-info.java\u201d-Datei).<\/p>\n\n\n\n<p>Genau wie benannte Module nicht auf Code im unbenannten Modul zugreifen k\u00f6nnen und so wie Code aus benannten Packages nicht auf unbenannte Packages zugreifen kann, kann auch Code aus benannten Klassen nicht auf unbenannte Klassen zugreifen.<\/p>\n\n\n\n<p>Die unbenannte Klasse darf \u00fcbrigens auch Felder und weitere Methoden haben. Auch das folgende ist ein g\u00fcltiges und vollst\u00e4ndiges Java-Programm:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-41\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">final<\/span> String HELLO_TEMPLATE = <span class=\"hljs-string\">\"Hello %s!\"<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n  System.out.println(hello(<span class=\"hljs-string\">\"world\"<\/span>));\n}\n\n<span class=\"hljs-function\">String <span class=\"hljs-title\">hello<\/span><span class=\"hljs-params\">(String name)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> HELLO_TEMPLATE.formatted(name);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-41\"><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\">Launch-Protokoll<\/h4>\n\n\n\n<div class=\"wp-block-uagb-info-box uagb-block-864ef8ae uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top hc-infobox\"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\">In <a href=\"\/de\/java\/java-22-features\/#Implicitly_Declared_Classes_and_Instance_Main_Methods_Second_Preview_JEP_463\">Java 22<\/a> wurde das Launch-Protokoll start vereinfacht, da sich viele der hier gezeigten Variationen der main()-Methode ohnehin gegenseitig ausschlie\u00dfen.<\/p><\/div><\/div>\n\n\n\n<p>Die <code>main()<\/code>-Methode darf nat\u00fcrlich auch weiterhin als <code>public static<\/code> markiert sein und das <code>String[]<\/code>-Argument enthalten. Sie darf auch nur <code>public<\/code> oder nur <code>static<\/code> sein. Oder auch <code>protected<\/code>. Theoretisch kann eine Klasse auch zwei <code>main()<\/code>-Methoden enthalten \u2013 beispielweise w\u00e4re auch folgendes erlaubt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-42\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-42\"><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>In so einem Fall entscheidet das sogenannte \"Launch-Protokoll\", welche der <code>main()<\/code>-Methoden gestartet wird. Das Launch-Protokoll sucht in folgender Reihenfolge; der Visibility-Modifier ist dabei irrelevant (nur <code>private<\/code> ist nicht erlaubt):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><code>static void main(String[] args)<\/code><\/li>\n\n\n\n<li><code>static void main()<\/code><\/li>\n\n\n\n<li><code>void main(String[] args)<\/code> \u2013 diese Methode darf auch von einer Oberklasse geerbt sein (das funktioniert allerdings nur in einer <em>benannten<\/em> Klasse)<\/li>\n\n\n\n<li><code>void main()<\/code> \u2013 auch diese Methode darf von einer Oberklasse geerbt sein<\/li>\n<\/ol>\n\n\n\n<p>Im Beispiel oben w\u00fcrde also die statische Methode ohne Parameter (Launch-Priorit\u00e4t 2) ausgef\u00fchrt werden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"scoped-values-preview-jep-446\">Scoped Values (Preview) \u2013 JEP 446<\/h3>\n\n\n\n<p>Scoped Values sind eine moderne Alternative zu <code>ThreadLocal<\/code>-Variablen, die sich sehr gut im Kontext <a href=\"\/de\/java\/virtual-threads\/\">virtueller Threads<\/a> einsetzen lassen.<\/p>\n\n\n\n<p>Scoped Values haben gegen\u00fcber <code>ThreadLocal<\/code>-Variablen den Vorteil, <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>dass sie nur f\u00fcr einen definierten Zeitraum (\u201eScope\u201d) g\u00fcltig sind, <\/li>\n\n\n\n<li>dass sie immutable sind und <\/li>\n\n\n\n<li>dass sie deswegen vererbt werden k\u00f6nnen ohne dabei kopiert werden zu m\u00fcssen (wie es bei <code>InheritableThreadLocal<\/code> der Fall ist).<\/li>\n<\/ul>\n\n\n\n<p>Die ersten beiden Punkte f\u00fchren zudem zu \u00fcbersichtlicherem und damit weniger fehleranf\u00e4lligem Programmcode.<\/p>\n\n\n\n<p>Scoped Values wurden in <a href=\"\/de\/java\/java-20-features\/#Scoped_Values_Incubator_-_JEP_429\">Java 20<\/a> im Incubator-Stadium vorgestellt und werden in Java 21 durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/446\" target=\"_blank\">JDK Enhancement Proposal 446<\/a> ohne weitere \u00c4nderungen ins Preview-Stadium \u00fcberf\u00fchrt.<\/p>\n\n\n\n<p>Wie Scoped Values genau funktionieren, erf\u00e4hrst du anhand eines Beispiels im <a href=\"\/de\/java\/scoped-values\/\">Hauptartikel \u00fcber Scoped Values<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"structured-concurrency-preview-jep-453\">Structured Concurrency (Preview) \u2013 JEP 453<\/h3>\n\n\n\n<p>Um eine Aufgabe in mehrere parallel abzuarbeitende Teilaufgaben aufzuteilen, stellt Java bisher zwei High-Level-Konstrukte zur Verf\u00fcgung:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Parallele Streams, um die gleiche Operation parallel auf mehreren Elementen auszuf\u00fchren<\/li>\n\n\n\n<li><code>ExecutorService<\/code>, um unterschiedliche Aufgaben parallel zu erledigen<\/li>\n<\/ul>\n\n\n\n<p><code>ExecutorService<\/code> ist sehr m\u00e4chtig, was den Implementierungsaufwand f\u00fcr einfache parallele Arbeiten schnell in die H\u00f6he treibt. Zum Beispiel ist es ziemlich kompliziert (und damit fehleranf\u00e4llig) zu erkennen, wenn eine Teilaufgabe eine Exception geworfen hat, um dann sofort alle anderen noch laufenden Teilaufgaben sauber abzubrechen.<\/p>\n\n\n\n<p>Mit Structured Concurrency wird ein neuer, einfach zu implementierender Mechanismus zur Verf\u00fcgung gestellt, um eine Aufgabe in parallel abzuarbeitende Teilaufgaben aufzuteilen, die Ergebnisse der Teilaufgaben zusammenzuf\u00fchren und Teilaufgaben abzubrechen, sollte deren Ergebnis nicht mehr ben\u00f6tigt werden.<\/p>\n\n\n\n<p>Wie das funktioniert, erf\u00e4hrst du im <a href=\"\/de\/java\/structured-concurrency-structuredtaskscope\/\">Hauptartikel \u00fcber Structured Concurrency<\/a>.<\/p>\n\n\n\n<p>Structured Concurrency wurde erstmals in <a href=\"\/de\/java\/java-19-features\/#Structured_Concurrency_Incubator_-_JEP_428\">Java 19<\/a> im Incubator-Stadium vorgestellt und in <a href=\"\/de\/java\/java-20-features\/#Structured_Concurrency_Second_Incubator_-_JEP_437\">Java 20<\/a> dahingehend erweitert, dass Subtasks die im vorherigen Abschnitt beschriebenen Scoped Values des Eltern-Threads erben.<\/p>\n\n\n\n<p>In Java 21 wurde durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/453\" target=\"_blank\">JDK Enhancement Proposal 453<\/a> der R\u00fcckgabetyp von <code>StructuredTaskScope.fork(...)<\/code> \u2013 also derjenigen Methode, die Subtasks startet \u2013 von <code>Future<\/code> in <code>Subtask<\/code> ge\u00e4ndert. Das soll den Unterschied von Structured Concurrency und der ExecutorService-API deutlich machen.<\/p>\n\n\n\n<p>Zum Beispiel wartet die <code>Future.get()<\/code>-Methode auf ein Ergebnis, w\u00e4hrend <code>Subtask.get()<\/code> erst dann aufgerufen werden darf, wenn ein Subtask beendet ist \u2013 andernfalls wirft die Methode eine <code>IllegalStateException<\/code>. Und <code>Subtask.state()<\/code> liefert einen Status zur\u00fcck, der spezifisch f\u00fcr Structured Concurrency ist, w\u00e4hrend <code>Future.isDone()<\/code> und <code>isCancelled()<\/code> dies nicht erm\u00f6glichen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"foreign-function-memory-api-third-preview-jep-442\">Foreign Function &amp; Memory API (Third Preview) \u2013 JEP 442<\/h3>\n\n\n\n<p>Wer bisher auf Code au\u00dferhalb der JVM (z. B. Funktionen in C-Bibliotheken) oder auf nicht von der JVM verwalteten Speicher zugreifen wollte, musste dazu das Java Native Interface (JNI) bem\u00fchen. Wer das schon einmal gemacht hat, wei\u00df, wie umst\u00e4ndlich, fehleranf\u00e4llig und langsam JNI ist.<\/p>\n\n\n\n<p>Bereits seit <a href=\"\/de\/java\/java-14-features\/#Foreign-Memory_Access_API_Incubator\">Java 14<\/a> wird \u2013 zun\u00e4chst in Incubator-Projekten \u2013 an einem Ersatz f\u00fcr JNI gearbeitet. In <a href=\"\/de\/java\/java-19-features\/#Foreign_Function_Memory_API_Preview_-_JEP_424\">Java 19<\/a> wurde dann die einheitliche \u201eForeign Function &amp; Memory API\u201d in einer ersten Preview-Version vorgestellt.<\/p>\n\n\n\n<p>Was diese API erm\u00f6glicht, demonstriere ich an einem einfachen Beispiel. <\/p>\n\n\n\n<p>Der folgende Code zeigt, wie du ein Handle auf die <code>strlen()<\/code>-Methode der Standard-C-Library beziehst, die Zeichenkette \u201eHappy Coding!\u201d im nativen Speicher (also au\u00dferhalb des Java-Heaps) ablegst und anschlie\u00dfend die <code>strlen()<\/code>-Methode auf diesem String ausf\u00fchrst:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-43\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FFMTest21<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <span class=\"hljs-keyword\">throws<\/span> Throwable <\/span>{\n    <span class=\"hljs-comment\">\/\/ 1. Get a lookup object for commonly used libraries<\/span>\n    SymbolLookup stdlib = Linker.nativeLinker().defaultLookup();\n\n    <span class=\"hljs-comment\">\/\/ 2. Get a handle to the \"strlen\" function in the C standard library<\/span>\n    MethodHandle strlen = Linker.nativeLinker().downcallHandle(\n        stdlib.find(<span class=\"hljs-string\">\"strlen\"<\/span>).orElseThrow(),\n        FunctionDescriptor.of(JAVA_LONG, ADDRESS));\n\n    <span class=\"hljs-comment\">\/\/ 3. Convert Java String to C string and store it in off-heap memory<\/span>\n    <span class=\"hljs-keyword\">try<\/span> (Arena offHeap = Arena.ofConfined()) {\n      MemorySegment str = offHeap.allocateUtf8String(<span class=\"hljs-string\">\"Happy Coding!\"<\/span>);\n\n      <span class=\"hljs-comment\">\/\/ 4. Invoke the foreign function<\/span>\n      <span class=\"hljs-keyword\">long<\/span> len = (<span class=\"hljs-keyword\">long<\/span>) strlen.invoke(str);\n\n      System.out.println(<span class=\"hljs-string\">\"len = \"<\/span> + len);\n    }\n    <span class=\"hljs-comment\">\/\/ 5. Off-heap memory is deallocated at end of try-with-resources<\/span>\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-43\"><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>Der Code unterscheidet sich von der <a href=\"\/de\/java\/java-20-features\/#Foreign_Function_Memory_API_Second_Preview_-_JEP_434\">Java-20<\/a>-Variante nur in einem Detail: Die <code>Arena.ofConfined()<\/code>-Methode hie\u00df zuvor <code>openConfined()<\/code>.<\/p>\n\n\n\n<p>Kompilieren und ausf\u00fchren kannst du das kleine Beispiel-Programm wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-44\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ javac --enable-preview --source 21 FFMTest21.java \nNote: FFMTest21.java uses preview features of Java SE 21.\nNote: Recompile with -Xlint:preview for details.\n\n$ java --enable-preview --enable-native-access=ALL-UNNAMED FFMTest21 \nlen = 13<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-44\"><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>Du kannst nat\u00fcrlich auch beide Schritte zu einem zusammenfassen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-45\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java --enable-preview --source 21 --enable-native-access=ALL-UNNAMED FFMTest21.java \nNote: FFMTest21.java uses preview features of Java SE 21.\nNote: Recompile with -Xlint:preview for details.\nlen = 13<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-45\"><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>Der Zugriff auf nativen Speicher und der Aufruf von nativen Code ist eher ein Spezialgebiet. Die wenigsten Programmierer werden damit direkt in Ber\u00fchrung kommen. Daher werde ich an dieser Stelle nicht weiter ins Detail gehen. Einzelheiten \u00fcber den aktuellen Stand der FFM-API findest du in <a href=\"https:\/\/openjdk.org\/jeps\/442\">JDK Enhancement Proposal 442<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vector-api-sixth-incubator-jep-448\">Vector API (Sixth Incubator) \u2013 JEP 448<\/h3>\n\n\n\n<p>Die neue Vector API wird in Java 21 durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/448\" target=\"_blank\">JDK Enhancement Proposal 448<\/a> zum sechsten Mal in Folge als Incubator-Version vorgelegt.<\/p>\n\n\n\n<p>Die Vector API wird es erm\u00f6glichen, mathematische Vektor-Operationen effizient auszuf\u00fchren. Eine Vektor-Operation ist z. B. eine Vektor-Addition, wie du sie vielleicht noch aus dem Mathematik-Unterricht kennst:<\/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 Vektor-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>Moderne CPUs k\u00f6nnen solche Operationen bis zu einer bestimmten Vektorgr\u00f6\u00dfe in einem einzigen CPU-Zyklus ausf\u00fchren. Die Vektor-API wird die JVM in die Lage versetzen, solche Operationen auf die effizientesten Instruktionen der zugrunde liegenden CPU-Architektur abzubilden.<\/p>\n\n\n\n<p>Ich werde die Vektor-API im Detail vorstellen, sobald sie dem Incubator-Stadium entwachsen ist und in der ersten Preview-Version vorliegt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-21\">Sonstige \u00c4nderungen in Java 21<\/h2>\n\n\n\n<p>Kommen wir zu den \u00c4nderungen, mit denen wir in der Regel nicht t\u00e4glich konfrontiert sein werden. Zumindest nicht direkt. Es sei denn, wir sind beispielsweise f\u00fcr die Auswahl des Garbage Collectors und dessen Optimierung zust\u00e4ndig. Dann d\u00fcrften die zwei folgenden JEPs interessant sein:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"generational-zgc-jep-439\">Generational ZGC \u2013 JEP 439<\/h3>\n\n\n\n<p>In <a href=\"\/de\/java\/java-15-features\/#ZGC_A_Scalable_Low-Latency_Garbage_Collector\">Java 15<\/a> wurde der Z Garbage Collector, kurz ZGC, eingef\u00fchrt. Dieser verspricht Pausenzeiten von weniger als 10 Millisekunden \u2013 was um bis zu Faktor 10 unter den Pausenzeiten des Standard-Garbage-Collectors G1GC liegt.<\/p>\n\n\n\n<p>Bisher machte ZGC keinen Unterschied zwischen \u201ealten\u201d und \u201eneuen\u201d Objekten. Genau dieser Unterschied kann aber laut der \u201eSchwachen Generationshypothese\u201d (englisch: \u201eWeak Generational Hypothesis\u201d) gro\u00dfen Einfluss auf die Performance einer Anwendung haben.<\/p>\n\n\n\n<p>Laut dieser Hypothese sterben die meisten Objekte kurz nach ihrer Erzeugung, wohingegen Objekte, die bereits einige GC-Zyklen \u00fcberlebt haben, in der Regel noch eine Weile l\u00e4nger am Leben bleiben. <\/p>\n\n\n\n<p>Das macht sich ein sogenannter \u201eGenerational Garbage Collector\u201d zunutze, indem er den Heap in zwei logische Bereiche aufteilt: eine \u201ejunge Generation\u201d, in der neue Objekte angelegt werden, und eine \u201ealte Generation\u201d, in die Objekte verschoben werden, die ein gewisses Alter erreicht haben. Da Objekte in der alten Generation mit hoher Wahrscheinlichkeit <em>noch<\/em> \u00e4lter werden, kann die Leistung einer Anwendung dadurch erh\u00f6ht werden, dass der Garbage Collector die alte Generation seltener scannt.<\/p>\n\n\n\n<p>Die Implementierung eines Garbage Collectors mit mehreren Generationen ist allerdings wegen der potentiellen Referenzen <em>zwischen<\/em> den Generationen deutlich aufw\u00e4ndiger als die Implementierung eines \u201eNon-generational GCs\u201d.<\/p>\n\n\n\n<p>Daher mussten wir bis Java 21 warten, bis mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/439\" target=\"_blank\">JDK Enhancement Proposal 439<\/a> der Z Garbage Collector zu einem \u201eGenerational Garbage Collector\u201d wurde.<\/p>\n\n\n\n<p>F\u00fcr eine \u00dcbergangsphase wird es beide Varianten des ZGC geben. Die VM-Option <code>-XX:+UseZGC<\/code> aktiviert nach wie vor die alte Variante ohne Generationen. Um die neue Variante mit Generationen zu aktivieren, m\u00fcssen folgende VM-Optionen angegeben werden:<\/p>\n\n\n\n<p class=\"has-text-align-center\"><code>-XX:+UseZGC -XX:+ZGenerational<\/code><\/p>\n\n\n\n<p>In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-23-features\/#ZGC_Generational_Mode_by_Default_-_JEP_474\">Java 23<\/a> wird die Variante mit Generationen zum Default werden, dann muss explizit mit <code>-XX:-ZGenerational<\/code> auf die Variante ohne Generationen umgeschaltet werden. Noch sp\u00e4ter sollen die Variante ohne Generationen und der <code>ZGenerational<\/code>-Parameter wieder entfernt werden.<\/p>\n\n\n\n<p>Wie genau der Generational ZGC funktioniert, kannst du in <a href=\"https:\/\/openjdk.org\/jeps\/439\" target=\"_blank\" rel=\"noopener\">JEP 439<\/a> nachlesen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecate-the-windows-32-bit-x86-port-for-removal-jep-449\">Deprecate the Windows 32-bit x86 Port for Removal \u2013 JEP&nbsp;449<\/h3>\n\n\n\n<p>Die 32-Bit-Version von Windows 10 wird kaum noch verwendet, der Support endet im Oktober 2025, und Windows 11 \u2013 seit Oktober 2021 auf dem Markt \u2013 wurde nie in einer 32-Bit-Version angeboten.<\/p>\n\n\n\n<p>Entsprechend besteht auch kaum noch Bedarf an einer 32-Bit-Windows-Version des JDK.<\/p>\n\n\n\n<p>Um die Entwicklung des JDK zu beschleunigen, wurden Virtuelle Threads bereits nicht mehr f\u00fcr 32-Bit-Windows implementiert. Wer auf 32-Bit-Windows einen virtuellen Thread starten will, bekommt einfach einen Plattform-Thread.<\/p>\n\n\n\n<p>Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/449\" target=\"_blank\">JDK Enhancement Proposal 449<\/a> wird die 32-Bit-Windows-Portierung als \u201edeprecated for removal\u201d markiert. Sie soll in einem zuk\u00fcnftigen Release vollst\u00e4ndig entfernt werden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"prepare-to-disallow-the-dynamic-loading-of-agents-jep-451\">Prepare to Disallow the Dynamic Loading of Agents \u2013 JEP&nbsp;451<\/h3>\n\n\n\n<p>Falls du schon einmal einen Java-Profiler verwendet hast, hast du die zu analysierende Anwendung wahrscheinlich mit einem Parameter wie <code>-agentpath:&lt;path-to-agent-library&gt;<\/code> gestartet. Dadurch wird ein sogenannter \u201eAgent\u201d in die Anwendung geladen, der diese zur Laufzeit so modifiziert, dass die n\u00f6tigen Messungen durchgef\u00fchrt und die Ergebnisse entweder in eine Datei geschrieben oder an das Frontend des Profilers geschickt werden.<\/p>\n\n\n\n<p>Falls die Anwendung ohne diesen Parameter gestartet wurde, kann der Agent auch nachtr\u00e4glich \u00fcber die sogenannte \u201eAttach API\u201d in die JVM \u201einjiziert\u201d werden.<\/p>\n\n\n\n<p>Dieses sogenannte \u201edynamische Laden\u201d ist standardm\u00e4\u00dfig aktiviert und stellt damit ein nicht unerhebliches Sicherheitsrisiko dar.<\/p>\n\n\n\n<p>In einer zuk\u00fcnftigen Java-Version soll das dynamische Laden daher standardm\u00e4\u00dfig deaktiviert sein und nur explizit \u00fcber die VM-Option <code>-XX:+EnableDynamicAgentLoading<\/code> aktivierbar sein.<\/p>\n\n\n\n<p>Da so eine \u00c4nderung nicht von heute auf morgen erfolgen kann, ist das dynamische Laden in Java 21 nach wie vor erlaubt, kann aber mit <code>-XX:-EnableDynamicAgentLoading<\/code> explizit deaktiviert werden. Zudem werden nun Warnungen angezeigt, wenn ein Agent \u00fcber die Attach API nachtr\u00e4glich geladen wird.<\/p>\n\n\n\n<p>Diese \u00c4nderung ist in <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/451\" target=\"_blank\">JDK Enhancement Proposal 451<\/a> definiert. Dort findest du auch eine detaillierte Auflistung der Sicherheitsrisiken.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"key-encapsulation-mechanism-api-jep-452\">Key Encapsulation Mechanism API \u2013 JEP 452<\/h3>\n\n\n\n<p>Key Encapsulation Mechanism (KEM) ist eine moderne Verschl\u00fcsselungstechnik, die den Austausch symmetrischer Schl\u00fcssel \u00fcber ein asymmetrisches Verschl\u00fcsselungsverfahren erm\u00f6glicht. KEMs sind so sicher, dass sie sogar zuk\u00fcnftigen Quantenangriffen standhalten sollen.<\/p>\n\n\n\n<p>Durch das <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/452\" target=\"_blank\">JDK Enhancement Proposal 452<\/a> stellt das JDK eine API f\u00fcr die Nutzung von KEM bereit.<\/p>\n\n\n\n<p>Die wenigsten von uns werden direkt mit der Implementierung von Ver- und Entschl\u00fcsselung konfrontiert. In der Regel nutzen wir sie nur indirekt, zum Beispiel durch die Verwendung von SSH oder den Zugriff auf eine HTTPS-Schnittstelle.<\/p>\n\n\n\n<p>Aus diesem Grund werde ich nicht detaillierter auf diesen JEP eingehen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"thread-sleepmillis-nanos-is-now-able-to-perform-sub-millisecond-sleeps\">Thread.sleep(millis, nanos) Is Now Able to Perform Sub-Millisecond Sleeps<\/h3>\n\n\n\n<p>Beim Aufruf von <code>Thread.sleep(millis, nanos)<\/code> wurde der <code>nanos<\/code>-Wert bisher quasi ignoriert. Es wurde lediglich, wenn <code>nanos<\/code> gr\u00f6\u00dfer als 500.000 (also eine halbe Millisekunde) war, der <code>millis<\/code>-Wert um eins erh\u00f6ht und dann <code>Thread.sleep(millis)<\/code> aufgerufen.<\/p>\n\n\n\n<p>Ab Java 21 wird die Wartezeit \u2013 zumindest auf Linux und macOS \u2013 auf Nanosekunden-Granularit\u00e4t ans Betriebssystem weitergegeben (bzw. im Falle eines virtuellen Threads an den \u201eUnparker\u201d). Die tats\u00e4chliche Wartezeit ist nach wie vor von der Pr\u00e4zision der Systemuhr und des Schedulers abh\u00e4ngig.<\/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-8305092\" target=\"_blank\" rel=\"noopener\">JDK-8305092<\/a> beschrieben.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"last-resort-g1-full-gc-moves-humongous-objects\">Last Resort G1 Full GC Moves Humongous Objects<\/h3>\n\n\n\n<p>Beim G1-Garbage-Collector (G1GC) wird der zur Verf\u00fcgung stehende Heap-Speicher in bis zu 2.048 Regionen aufgeteilt. Objekte, die gr\u00f6\u00dfer als die H\u00e4lfte einer solchen Region sind, werden als \u201ehumongous objects\u201d (zu deutsch: \u201eriesige Objekte\u201d) bezeichnet. <\/p>\n\n\n\n<p>Humongous objects wurden bisher niemals im Speicher verschoben. So konnte es bei starker Fragmentierung des Heaps zu einem <code>OutOfMemoryError<\/code> kommen, selbst wenn insgesamt noch ausreichend Speicher zur Verf\u00fcgung stand \u2013 nur eben nicht in einem zusammenh\u00e4ngenden Bereich.<\/p>\n\n\n\n<p>Ab Java 21 werden nun auch riesige Objekte verschoben \u2013 allerdings erst dann, wenn nach einem Full GC nicht ausreichend zusammenh\u00e4ngender Speicher zur Verf\u00fcgung steht. Dieser Vorgang kann je nach Gr\u00f6\u00dfe des Heaps ziemlich lange (bis zu mehreren Sekunden) in Anspruch nehmen.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung gibt es keinen JEP; sie ist im Bug Tracker unter <\/em><a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8191565\" target=\"_blank\" rel=\"noopener\">JDK-8191565<\/a><em> beschrieben.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"implement-alternative-fast-locking-scheme\">Implement Alternative Fast-Locking Scheme<\/h3>\n\n\n\n<p>Wenn ein Thread einen <code>synchronized<\/code>-Block auf einem Objekt betritt, muss die JVM diese Information irgendwo speichern, um zu verhindern, dass ein anderer Thread den kritischen Bereich betritt.<\/p>\n\n\n\n<p>Dies geschieht bisher \u00fcber einen Mechanismus, der sich \u201e<a href=\"https:\/\/www.happycoders.eu\/de\/java\/object-headers-compressed-class-pointers\/#legacy-stack-locking\">Stack Locking<\/a>\u201c nennt. Dabei wird das <a href=\"https:\/\/www.happycoders.eu\/de\/java\/object-headers-compressed-class-pointers\/#mark-word\">Mark Word des Objekt Headers<\/a> durch einen Pointer auf eine Datenstruktur auf dem Stack ersetzt, die dann wiederum das Mark Word und weitere Informationen \u00fcber den Lock-Zustand enth\u00e4lt.<\/p>\n\n\n\n<p>Dieser Mechanismus erschwert zum einen den Zugriff auf die eigentlichen Daten des Mark Words. Zum anderen ist der Pointer auf den Stack mit ein Grund f\u00fcr das sogenannte <a href=\"https:\/\/www.happycoders.eu\/de\/java\/virtual-threads\/#2-pinning\">Pinning von virtuellen Threads<\/a>.<\/p>\n\n\n\n<p>In Java 21 wird ein alternativer Locking-Mechanismus angeboten, das sogenannte \u201e<a href=\"https:\/\/www.happycoders.eu\/de\/java\/object-headers-compressed-class-pointers\/#lightweight-locking\">Lightweight Locking<\/a>\u201c. Dabei wird lediglich die zwei \u201eTag Bits\u201c im Mark Word gesetzt; zus\u00e4tzliche Lock-Datenstukturen werden in einer Hashtable und einem Thread-lokalen Cache abgelegt. Auf das Mark Word kann so immer direkt zugegriffen werden.<\/p>\n\n\n\n<p><em>Lightweight Locking<\/em> kann \u00fcber die im n\u00e4chsten Abschnitt beschriebene VM-Option aktiviert werden.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung gibt es keinen JEP; sie ist im Bug Tracker unter <\/em><a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8291555\" target=\"_blank\" rel=\"noreferrer noopener\">JDK-8291555<\/a><em> beschrieben.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"add-experimental-xxlockingmode-flag\">Add Experimental -XX:LockingMode Flag<\/h3>\n\n\n\n<p>Locking erfolgt in der Regel in zwei Schritten:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Sobald ein Thread einen kritischen Bereich betritt, wird zun\u00e4chst nur im Monitor-Objekt (das Objekt, das hinter <code>synchronized<\/code> in Klammern angegeben wird) die Information gespeichert, <em>dass<\/em> der Bereich gelockt ist \u2013 weitere Informationen sind zu diesem Zeitpunkt nicht n\u00f6tig.<\/li>\n\n\n\n<li>Erst wenn ein weiterer Thread versucht, den kritischen Bereich zu betreten, muss u. a. eine Liste der wartenden Threads angelegt werden. Daf\u00fcr wird dann eine zus\u00e4tzliche Datenstruktur erzeugt, der sogenannte \u201eschwergewichtige Monitor\u201c.<\/li>\n<\/ol>\n\n\n\n<p>Schritt 1 erfolgte bisher durch das sogenannte \u201e<a href=\"https:\/\/www.happycoders.eu\/de\/java\/object-headers-compressed-class-pointers\/#legacy-stack-locking\">Stack Locking<\/a>\u201c. Durch die VM-Option <code style=\"white-space:nowrap\">-XX:+UseHeavyMonitors<\/code> konnte Schritt 1 \u00fcbersprungen und direkt der \u201eschwergewichtige Monitor\u201c erzeugt werden.<\/p>\n\n\n\n<p>Um den im vorherigen Abschnitt beschriebenen neuen Locking-Mechanismus zu aktivieren, wird die VM-Option <code>-XX:LockingMode<\/code> eingef\u00fchrt, mit den folgenden Optionen:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><thead><tr><th>VM-Option<\/th><th>Bezeichnung<\/th><th>Erl\u00e4uterung<\/th><\/tr><\/thead><tbody><tr><td><code style=\"white-space:nowrap\">-XX:LockingMode=0<\/code><\/td><td>LM_MONITOR<\/td><td>Ausschlie\u00dflich schwergewichtige Monitor-Objekte (Schritt 1 wird \u00fcbersprungen); entspricht der bisherigen Option <code style=\"white-space:nowrap\">-XX:+UseHeavyMonitors<\/code><\/td><\/tr><tr><td><code style=\"white-space:nowrap\">-XX:LockingMode=1<\/code><\/td><td>LM_LEGACY<\/td><td><em>Stack Locking<\/em> + Monitor-Objekte bei Contention; enspricht dem bisherigen Standardverhalten<\/td><\/tr><tr><td><code style=\"white-space:nowrap\">-XX:LockingMode=2<\/code><\/td><td>LM_LIGHTWEIGHT<\/td><td><em>Lightweight Locking<\/em> + Monitor-Objekte bei Contention; dies ist der neue, im vorherigen Abschnitt beschriebene Modus.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Da sich das Feature aktuell noch im experimentellen Stadium befindet, muss zus\u00e4tzlich die VM-Option <code style=\"white-space:nowrap\">-XX:+UnlockExperimentalVMOptions<\/code> angegeben werden.<\/p>\n\n\n\n<p>In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-23-features\/#Change_LockingMode_default_from_LM_LEGACY_to_LM_LIGHTWEIGHT\">Java 23<\/a> wird das neue, leichtgewichtige Locking zum Standard-Modus werden.<\/p>\n\n\n\n<p>In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#Deprecate_LockingMode_Option_along_with_LM_LEGACY_and_LM_MONITOR\">Java 24<\/a> soll die VM-Option <code>-XX:LockingMode<\/code> als \u201edeprecated\u201c markiert werden, in Java 26 soll sie keine Funktion mehr haben, und in Java 27 soll sie wieder entfernt werden.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung gibt es keinen JEP; sie ist im Bug Tracker unter <\/em><a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8305999\" target=\"_blank\" rel=\"noreferrer noopener\">JDK-8305999<\/a><em> beschrieben.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-21\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 21<\/h3>\n\n\n\n<p>In diesem Artikel hast du alle Java Enhancement Proposals kennengelernt, die in Java 21 umgesetzt wurden. Weitere kleinere \u00c4nderungen findest du in den offiziellen <a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/21all-relnotes.html\" target=\"_blank\" rel=\"noopener\">Java 21 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>Das neue LTS-Release Java 21 bringt mit der Finalisierung von Virtuellen Threads eine der bedeutendsten Ver\u00e4nderungen der Java-Geschichte, die die Implementierung von hochskalierbaren Serveranwendungen deutlich vereinfachen wird. <\/p>\n\n\n\n<p><em>Record Patterns<\/em>, <em>Pattern Matching for switch<\/em>, <em>Sequenced Collections<\/em>, <em>String Templates<\/em> und <em>Unnamed Patterns and Variables<\/em> (die letzten zwei davon noch im Preview-Stadium) machen die Sprache ausdrucksst\u00e4rker und robuster.<\/p>\n\n\n\n<p><em>Unnamed Classes and Instance Main Methods<\/em> (ebenfalls im Preview-Stadium) erleichtern Programmiererinnen und Programmierern den Einstieg in die Sprache, ohne gleich zu Beginn komplexe Konstrukte wie Klassen und statische Methoden verstehen zu m\u00fcssen.<\/p>\n\n\n\n<p>Diverse sonstige \u00c4nderungen runden wie immer das Release ab. Die aktuelle Java-21-Version kannst du <a href=\"https:\/\/jdk.java.net\/21\/\" target=\"_blank\" rel=\"noopener\">hier<\/a> (OpenJDK) und <a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/jdk21-archive-downloads.html\" target=\"_blank\" rel=\"noopener\">hier<\/a> (Oracle) herunterladen.<\/p>\n\n\n\n<p>Auf welches Java-21-Feature freust du dich am meisten? Welches Feature vermisst du? Lasse es mich gerne \u00fcber die Kommentarfunktion wissen!<\/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>Die neuen Java 21 Features mit Beispielen: Virtual Threads, Sequenced Collections, Record Patterns, Pattern Matching for switch; neue Previews: String Templates, Unnamed Patterns and Variables, Unnamed Classes and Instance Main Methods ... und mehr!<\/p>\n","protected":false},"author":1,"featured_media":35616,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"","_seopress_titles_title":"","_seopress_titles_desc":"Alle Java 21 Features: Virtuelle Threads, Sequenced Collections, Record Patterns, Pattern Matching, String Templates, Unnamed Variables + mehr!","_seopress_robots_index":"","_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":51042,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-35614","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\/2023\/06\/java-21-features.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/06\/java-21-features.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":2,"uagb_excerpt":"Die neuen Java 21 Features mit Beispielen: Virtual Threads, Sequenced Collections, Record Patterns, Pattern Matching for switch; neue Previews: String Templates, Unnamed Patterns and Variables, Unnamed Classes and Instance Main Methods ... und mehr!","public_identification_id":"2026496f6629439a87d34802dbb3e32c","private_identification_id":"d52d96b854cb425f9bfd6d755e49588e","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/35614","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=35614"}],"version-history":[{"count":11,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/35614\/revisions"}],"predecessor-version":[{"id":54374,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/35614\/revisions\/54374"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/35616"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=35614"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=35614"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=35614"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}