{"id":33905,"date":"2023-03-21T09:00:00","date_gmt":"2023-03-21T08:00:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=33905"},"modified":"2025-11-29T19:30:18","modified_gmt":"2025-11-29T18:30:18","slug":"java-20-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-20-features\/","title":{"rendered":"Java 20 Features (mit Beispielen)"},"content":{"rendered":"\n<p>Java 20 wurde am 21. M\u00e4rz 2023 ver\u00f6ffentlicht. Du kannst es <a href=\"https:\/\/jdk.java.net\/20\/\">hier<\/a> herunterladen.<\/p>\n\n\n\n<p>Nachdem wir in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-19-features\/\">Java 19<\/a> mit <a href=\"https:\/\/www.happycoders.eu\/de\/java\/virtual-threads\/\">virtuellen Threads<\/a> eine der gr\u00f6\u00dften Erweiterungen der Java-Geschichte  ausprobieren durften, f\u00e4llt das Java-20-Release wieder etwas kleiner aus.<\/p>\n\n\n\n<p>Die interessanteste Neuerung nennt sich <a href=\"#Scoped_Values_Incubator_-_JEP_429\">\"Scoped Values\"<\/a> und soll in zahlreichen Einsatzzwecken die mit diversen Nachteilen behafteten Thread-Local-Variablen ersetzen. <\/p>\n\n\n\n<p>Die restlichen f\u00fcnf der sechs in Java 20 ver\u00f6ffentlichten JEPs sind Wiedervorlagen bereits bekannter Incubator- und Preview-Features.<\/p>\n\n\n\n<p>Ich verwende wie immer ausschlie\u00dflich die englischen Bezeichnungen der JEPs.<\/p>\n\n\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>Bei allen sechs JDK Enhancement Proposals (JEPs), die es in das Java-20-Release geschafft haben, handelt es sich um Incubator- bzw. Preview-Features. Das sind noch nicht fertiggestellte Features, die explizit (mit <code>--enable-preview<\/code> bei den <code>java<\/code> und <code>javac<\/code> Kommandos) aktiviert werden m\u00fcssen, um sie testen zu k\u00f6nnen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"scoped-values-incubator-jep-429\">Scoped Values (Incubator) \u2013 JEP 429<\/h3>\n\n\n\n<p>Scoped Values \u2013 genau wie <a href=\"\/de\/java\/virtual-threads\/\">virtuelle Threads<\/a> in <a href=\"https:\/\/openjdk.org\/projects\/loom\/\" target=\"_blank\" rel=\"noopener\">Project Loom<\/a> entwickelt \u2013 sind eine moderne und insbesondere mit virtuellen Threads gut kombinierbare Alternative zu Thread Locals. Sie erm\u00f6glichen es, einen Wert f\u00fcr einen begrenzten Zeitraum so zu speichern, dass nur derjenige Thread den Wert lesen kann, der ihn geschrieben hat.<\/p>\n\n\n\n<p>Mit dem <a href=\"https:\/\/openjdk.org\/jeps\/429\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 429<\/a> werden Scoped Values in Java 20 erstmals im Incubator-Stadium vorgestellt.<\/p>\n\n\n\n<p>Wie Scoped Values genau funktionieren und warum sie gegen\u00fcber Thread Locals vorzuziehen sind, erf\u00e4hrst du 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=\"record-patterns-second-preview-jep-432\">Record Patterns (Second Preview) \u2013 JEP 432<\/h3>\n\n\n\n<p>Record Patterns wurden erstmals in <a href=\"\/de\/java\/java-19-features\/#Record_Patterns_Preview_-_JEP_405\">Java 19<\/a> vorgestellt. Ein Record Pattern kann mit <code>instanceof<\/code> oder <code>switch<\/code> verwendet werden, um ohne Cast und Aufruf von Zugriffsmethoden auf die Felder eines Records zuzugreifen. <\/p>\n\n\n\n<p>Hier ein einfacher Beispiel-Record:<\/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-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-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>Mittels Record Pattern k\u00f6nnen wir nun einen <code>instanceof<\/code>-Ausdruck wie folgt schreiben:<\/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\">Object object = ...\n\n<span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">object <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.println(<span class=\"hljs-string\">\"object is a position, x = \"<\/span> + x + <span class=\"hljs-string\">\", y = \"<\/span> + y);\n} <\/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>Wir k\u00f6nnen somit \u2013 sofern <code>object<\/code> vom Typ <code>Position<\/code> ist \u2013 direkt auf dessen x- und y-Werte zugreifen.<\/p>\n\n\n\n<p>Das gleiche funktioniert in einem switch-Ausdruck:<\/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\">Object object = ...\n\n<span class=\"hljs-keyword\">switch<\/span> (object) {\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> \n      -&gt; System.out.<span class=\"hljs-title\">println<\/span><span class=\"hljs-params\">(<span class=\"hljs-string\">\"object is a position, x = \"<\/span> + x + <span class=\"hljs-string\">\", y = \"<\/span> + y)<\/span><\/span>;\n\n  <span class=\"hljs-comment\">\/\/ other cases ...<\/span>\n}<\/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>Mit dem <a href=\"https:\/\/openjdk.org\/jeps\/432\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 432<\/a> wurden in Java 20 folgende \u00c4nderungen ver\u00f6ffentlicht:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Inferenz von Typargumenten generischer Record Patterns<\/h4>\n\n\n\n<p>Um diese \u00c4nderung zu erkl\u00e4ren, brauchen wir ein komplexeres Beispiel.<\/p>\n\n\n\n<p>Gegeben seien ein generisches Interface <code>Multi&lt;T&gt;<\/code> und zwei implementierende Records, <code>Tuple&lt;T&gt;<\/code> und <code>Triple&lt;T&gt;<\/code>, die zwei bzw. drei Werte des Typs <code>T<\/code> enthalten:<\/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-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">Multi<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt; <\/span>{}\n\nrecord Tuple&lt;T&gt;(T t1, T t2) implements Multi&lt;T&gt; {}\n\nrecord Triple&lt;T&gt;(T t1, T t2, T t3) implements Multi&lt;T&gt; {}<\/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>Mit folgendem Code k\u00f6nnen wir pr\u00fcfen, um welche konkrete Implementierung es sich bei einem gegebenen <code>Multi<\/code>-Objekt handelt:<\/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\">Multi&lt;String&gt; multi = ...\n\n<span class=\"hljs-keyword\">if<\/span> (multi <span class=\"hljs-keyword\">instanceof<\/span> Tuple&lt;String&gt;(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2)) {\n  System.out.println(<span class=\"hljs-string\">\"Tuple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2);\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (multi <span class=\"hljs-keyword\">instanceof<\/span> Triple&lt;String&gt;(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2, <span class=\"hljs-keyword\">var<\/span> s3)) {\n  System.out.println(<span class=\"hljs-string\">\"Triple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2 + <span class=\"hljs-string\">\", \"<\/span> + s3);\n}<\/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>Dabei m\u00fcssen wir den Typ-Parameter (in diesem Fall <code>String<\/code>) bei jeder <code>instanceof<\/code>-Pr\u00fcfung mit angeben.<\/p>\n\n\n\n<p>Ab Java 20 kann der Compiler den Typ herleiten, so dass wir ihn bei den <code>instanceof<\/code>-Pr\u00fcfungen weglassen k\u00f6nnen:<\/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-keyword\">if<\/span> (<span class=\"hljs-function\">multi <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-title\">Tuple<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2)<\/span>) <\/span>{\n  System.out.println(<span class=\"hljs-string\">\"Tuple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2);\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">multi <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-title\">Triple<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2, <span class=\"hljs-keyword\">var<\/span> s3)<\/span>) <\/span>{\n  System.out.println(<span class=\"hljs-string\">\"Triple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2 + <span class=\"hljs-string\">\", \"<\/span> + s3);\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>Was mir dabei nicht gef\u00e4llt, ist dass hier die Syntax der sogenannten \"Raw Types\" verwendet wird. Raw Types f\u00fchren normalerweise dazu, dass der Compiler jegliche Typinformation ignoriert. Das ist hier aber nicht der Fall.<\/p>\n\n\n\n<p>Ich hielte es daher f\u00fcr konsistenter, hier den Diamond-Operator zu verwenden:<\/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-keyword\">if<\/span> (multi <span class=\"hljs-keyword\">instanceof<\/span> Tuple&lt;&gt;(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2)) {\n  System.out.println(<span class=\"hljs-string\">\"Tuple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2);\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (multi <span class=\"hljs-keyword\">instanceof<\/span> Triple&lt;&gt;(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2, <span class=\"hljs-keyword\">var<\/span> s3)) {\n  System.out.println(<span class=\"hljs-string\">\"Triple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2 + <span class=\"hljs-string\">\", \"<\/span> + s3);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Auch bei switch-Statements kann der Typ-Parameter ab Java 20 weggelassen werden.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Record Patterns in for-Schleifen<\/h4>\n\n\n\n<p>Nehmen wir an, wir haben eine Liste von Positionen und wollen diese auf der Konsole ausgeben. Das konnten wir bisher so machen:<\/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\">List&lt;Position&gt; positions = ...\n\n<span class=\"hljs-keyword\">for<\/span> (Position p : positions) {\n  System.out.printf(<span class=\"hljs-string\">\"(%d, %d)%n\"<\/span>, p.x(), p.y());\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>Ab Java 20 k\u00f6nnen wir in der for-Schleife auch ein Record Pattern angeben und dann (genau wie bei <code>instanceof<\/code> und <code>switch<\/code>) direkt auf <code>x<\/code> und <code>y<\/code> zugreifen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">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-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\">Entfernung der Unterst\u00fctzung f\u00fcr benannte Record Patterns<\/h4>\n\n\n\n<p>Bisher gab es folgende drei M\u00f6glichkeiten, Pattern Matching mit einem Record durchzuf\u00fchren:<\/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\">Object object =  <span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">3<\/span>);\n\n<span class=\"hljs-comment\">\/\/ 1. Pattern Matching for instanceof<\/span>\n<span class=\"hljs-keyword\">if<\/span> (object <span class=\"hljs-keyword\">instanceof<\/span> Position p) {\n  System.out.println(<span class=\"hljs-string\">\"object is a position, p.x = \"<\/span> + p.x() + <span class=\"hljs-string\">\", p.y = \"<\/span> + p.y());\n}\n\n<span class=\"hljs-comment\">\/\/ 2. Record Pattern<\/span>\n<span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">object <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.println(<span class=\"hljs-string\">\"object is a position, x = \"<\/span> + x + <span class=\"hljs-string\">\", y = \"<\/span> + y);\n}\n\n<span class=\"hljs-comment\">\/\/ 3. Named Record Pattern<\/span>\n<span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-function\">object <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> p) <\/span>{\n  System.out.println(<span class=\"hljs-string\">\"object is a position, p.x = \"<\/span> + p.x() + <span class=\"hljs-string\">\", p.y = \"<\/span> + p.y() \n                                         + <span class=\"hljs-string\">\", x = \"<\/span> + x + <span class=\"hljs-string\">\", y = \"<\/span> + y);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Bei der dritten Variante (\"Named Record Pattern\") gibt es zwei Wege, um auf die Felder des Records zuzugreifen \u2013 entweder \u00fcber die Variablen <code>x<\/code> und <code>y<\/code> \u2013 oder \u00fcber <code>p.x()<\/code> und <code>p.y()<\/code>. <\/p>\n\n\n\n<p>Diese Variante wurde f\u00fcr \u00fcberfl\u00fcssig befunden und daher in Java 20 wieder entfernt.<\/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<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"pattern-matching-for-switch-fourth-preview-jep-433\">Pattern Matching for switch (Fourth Preview) \u2013 JEP 433<\/h3>\n\n\n\n<p>Das n\u00e4chste Feature hat bereits drei Preview-Runden hinter sich. \"Pattern Matching for Switch\" wurde in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-17-features\/#Pattern_Matching_for_switch_Preview\">Java 17<\/a> erstmals vorgestellt und erm\u00f6glicht es uns, ein switch-Statement wie das folgende zu schreiben:<\/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\">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\">Pos<\/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-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>So k\u00f6nnen wir in einem switch-Statement pr\u00fcfen, ob ein Objekt von einer bestimmten Klasse ist (und ggf. weiteren Bedingungen gen\u00fcgt) und dieses Objekt gleichzeitig implizit auf die Zielklasse casten. Wir k\u00f6nnen das switch-Statement auch mit Record-Patterns kombinieren und so direkt auf die Record-Felder zugreifen.<\/p>\n\n\n\n<p>Mit dem <a href=\"https:\/\/openjdk.org\/jeps\/433\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 433<\/a> wurden in Java 20 folgende \u00c4nderungen gemacht:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">MatchException bei ersch\u00f6pfendem Switch<\/h4>\n\n\n\n<p>Ein ersch\u00f6pfender Switch (also ein Switch, der alle m\u00f6glichen Werte umfasst) wirft eine <code>MatchException<\/code> (und nicht wie zuvor einen <code>IncompatibleClassChangeError<\/code>), wenn zur Laufzeit festgestellt wird, dass kein Switch-Label zutrifft.<\/p>\n\n\n\n<p>Das kann dann passieren, wenn der Code nachtr\u00e4glich erweitert wird, aber nicht alle Klassen neu compiliert werden. Am besten zeige ich das an einem Beispiel:<\/p>\n\n\n\n<p>Unter Verwendung des <code>Position<\/code>-Records aus dem <a href=\"#Record_Patterns_Second_Preview_-_JEP_432\">Record-Pattern-Kapitel<\/a> definieren wir ein <a href=\"https:\/\/www.happycoders.eu\/de\/java\/sealed-classes\/\">versiegeltes Interface<\/a> <code>Shape<\/code> mit den Implementierungen <code>Rectangle<\/code> und <code>Circle<\/code>:<\/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-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>{}<\/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>Zus\u00e4tzlich schreiben wir einen <code>ShapeDebugger<\/code>, der je nach <code>Shape<\/code>-Implementierung unterschiedliche Debug-Infos ausgibt:<\/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-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.println(\n        <span class=\"hljs-string\">\"Rectangle: top left = \"<\/span> + r.topLeft() + <span class=\"hljs-string\">\"; bottom right = \"<\/span> + r.bottomRight());\n\n      <span class=\"hljs-keyword\">case<\/span> Circle c -&gt; System.out.println(\n        <span class=\"hljs-string\">\"Circle: center = \"<\/span> + c.center() + <span class=\"hljs-string\">\"; radius = \"<\/span> + c.radius());\n    }\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>Da der Compiler alle m\u00f6glichen Implementierungen des versiegelten <code>Shape<\/code>-Interfaces kennt, kann er sicherstellen, dass dieser Switch-Ausdruck ersch\u00f6pfend ist.<\/p>\n\n\n\n<p>Mit folgendem Programm rufen wir den <code>ShapeDebugger<\/code> auf:<\/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> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Main<\/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    <span class=\"hljs-keyword\">var<\/span> rectangle = <span class=\"hljs-keyword\">new<\/span> Rectangle(<span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">10<\/span>, <span class=\"hljs-number\">10<\/span>), <span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">50<\/span>, <span class=\"hljs-number\">50<\/span>));\n    ShapeDebugger.debug(rectangle);\n\n    <span class=\"hljs-keyword\">var<\/span> circle = <span class=\"hljs-keyword\">new<\/span> Circle(<span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">30<\/span>, <span class=\"hljs-number\">30<\/span>), <span class=\"hljs-number\">10<\/span>);\n    ShapeDebugger.debug(circle);\n  }\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>Wir compilieren den Code wie folgt und f\u00fchren die Main-Klasse aus:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ javac --enable-preview --source 20 *.java\n$ java --enable-preview Main\n\nRectangle: top left = Position&#091;x=10, y=10]; bottom right = Position&#091;x=50, y=50]\nCircle: center = Position&#091;x=30, y=30]; radius = 10<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Danach f\u00fcgen wir eine weitere Form <code>Oval<\/code> hinzu, tragen diese in die <code>permits<\/code>-Liste des <code>Shape<\/code>-Interfaces ein und erweitern das Hauptprogramm:<\/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-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 class=\"hljs-title\">Oval<\/span> <\/span>{}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> record <span class=\"hljs-title\">Oval<\/span><span class=\"hljs-params\">(Position center, <span class=\"hljs-keyword\">int<\/span> width, <span class=\"hljs-keyword\">int<\/span> height)<\/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\">Main<\/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    <span class=\"hljs-keyword\">var<\/span> rectangle = <span class=\"hljs-keyword\">new<\/span> Rectangle(<span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">10<\/span>, <span class=\"hljs-number\">10<\/span>), <span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">50<\/span>, <span class=\"hljs-number\">50<\/span>));\n    ShapeDebugger.debug(rectangle);\n\n    <span class=\"hljs-keyword\">var<\/span> circle = <span class=\"hljs-keyword\">new<\/span> Circle(<span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">30<\/span>, <span class=\"hljs-number\">30<\/span>), <span class=\"hljs-number\">10<\/span>);\n    ShapeDebugger.debug(circle);\n\n    <span class=\"hljs-keyword\">var<\/span> oval = <span class=\"hljs-keyword\">new<\/span> Oval(<span class=\"hljs-keyword\">new<\/span> Position(<span class=\"hljs-number\">60<\/span>, <span class=\"hljs-number\">60<\/span>), <span class=\"hljs-number\">20<\/span>, <span class=\"hljs-number\">10<\/span>);\n    ShapeDebugger.debug(oval);\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>Wenn wir das in einer IDE machen, wird diese uns sofort mitteilen, dass das Switch-Statement im <code>ShapeDebugger<\/code> nicht alle m\u00f6glichen Werte abdeckt:<\/p>\n\n\n\n<figure class=\"wp-block-image 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 20, JEP 433: IDE-Fehlermeldung bei ersch\u00f6pfendem Switch\" 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\n\n\n<p>Wenn wir allerdings ohne IDE arbeiten, nur die ge\u00e4nderten Klassen neu kompilieren und dann das Hauptprogramm starten, passiert folgendes:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ javac --enable-preview --source 20 Shape.java Oval.java Main.java\n$ java --enable-preview Main\n\nRectangle: top left = Position&#091;x=10, y=10]; bottom right = Position&#091;x=50, y=50]\nCircle: center = Position&#091;x=30, y=30]; radius = 10\nException in thread \"main\" java.lang.MatchException\n        at ShapeDebugger.debug(ShapeDebugger.java:3)\n        at Main.main(Main.java:10)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><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>Zur Laufzeit kommt es nun zu einer <code>MatchException<\/code>, da der Switch-Ausdruck im <code>ShapeDebugger<\/code> kein Label f\u00fcr die <code>Oval<\/code>-Klasse hat. <\/p>\n\n\n\n<p>Das gleiche kann bei einem ersch\u00f6pfenden Switch-Ausdruck \u00fcber alle Werte eines Enums passieren, wenn wir nachtr\u00e4glich das Enum erweitern.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Inferenz von Typargumenten f\u00fcr generische Record Patterns<\/h4>\n\n\n\n<p>Wie bei den zuvor besprochenen <a href=\"#Record_Patterns_Second_Preview_-_JEP_432\">Record Patterns<\/a> mit <code>instanceof<\/code>, k\u00f6nnen nun auch in Switch-Ausdr\u00fccken die Typargumente generischer Records vom Compiler hergeleitet werden.<\/p>\n\n\n\n<p>Bisher mussten wir ein Switch-Statement (basierend auf den Beispielklassen aus dem Record-Patterns-Kapitel) wie folgt schreiben:<\/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\">Multi&lt;String&gt; multi = ...\n\n<span class=\"hljs-keyword\">switch<\/span>(multi) {\n  <span class=\"hljs-keyword\">case<\/span> Tuple&lt;String&gt;(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2) -&gt;  System.out.println(\n          <span class=\"hljs-string\">\"Tuple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2);\n\n  <span class=\"hljs-keyword\">case<\/span> Triple&lt;String&gt;(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2, <span class=\"hljs-keyword\">var<\/span> s3) -&gt;  System.out.println(\n          <span class=\"hljs-string\">\"Triple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2 + <span class=\"hljs-string\">\", \"<\/span> + s3);\n\n  ...\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>Ab Java 20 k\u00f6nnen wir die Typ-Argumente <code>&lt;String&gt;<\/code> innerhalb des Switch-Statements weglassen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">switch<\/span>(multi) {\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Tuple<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2)<\/span> -&gt;  System.out.<span class=\"hljs-title\">println<\/span><span class=\"hljs-params\">(\n          <span class=\"hljs-string\">\"Tuple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2)<\/span><\/span>;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-title\">Triple<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">var<\/span> s1, <span class=\"hljs-keyword\">var<\/span> s2, <span class=\"hljs-keyword\">var<\/span> s3)<\/span> -&gt;  System.out.<span class=\"hljs-title\">println<\/span><span class=\"hljs-params\">(\n          <span class=\"hljs-string\">\"Triple: \"<\/span> + s1 + <span class=\"hljs-string\">\", \"<\/span> + s2 + <span class=\"hljs-string\">\", \"<\/span> + s3)<\/span><\/span>;\n\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"foreign-function-memory-api-second-preview-jep-434\">Foreign Function &amp; Memory API (Second Preview) \u2013 JEP 434<\/h3>\n\n\n\n<p>An der in <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/projects\/panama\/\" target=\"_blank\">Project Panama<\/a> entwickelten \"Foreign Function &amp; Memory API\" wird bereits seit <a href=\"\/de\/java\/java-14-features\/\">Java 14<\/a> gearbeitet \u2013 damals noch in zwei separate JEPs \"Foreign Memory Access API\" und \"Foreign Linker API\".<\/p>\n\n\n\n<p>Seit <a href=\"\/de\/java\/java-19-features\/\">Java 19<\/a> befindet sich die vereinheitlichte API im Preview-Stadium. Ihr Ziel ist es, langfristig das umst\u00e4ndlich zu benutzende, fehleranf\u00e4llige und langsame Java Native Interface (JNI) abl\u00f6sen.<\/p>\n\n\n\n<p>Die API erm\u00f6glicht es, aus Java heraus auf nativen Speicher (also Speicher au\u00dferhalb des Java-Heaps) zuzugreifen und nativen Code (z. B. aus C-Libraries) auszuf\u00fchren.<\/p>\n\n\n\n<p>Mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/434\" target=\"_blank\">JDK Enhancement Proposal 434<\/a> wurden einige \u00c4nderungen an der API durchgef\u00fchrt \u2013 mehr als normalerweise f\u00fcr Preview-Features \u00fcblich. Da ich im Java-19-Artikel die Foreign Function &amp; Memory API nicht im Detail erkl\u00e4rt habe, werde ich auch hier nicht auf die einzelnen \u00c4nderungen eingehen.<\/p>\n\n\n\n<p>Stattdessen wiederhole ich das <a href=\"\/de\/java\/java-19-features\/#Foreign_Function_Memory_API_Preview_-_JEP_424\">Beispiel aus dem Java-19-Artikel<\/a>, angepasst an die \u00c4nderungen in Java 20. Das Beispiel-Programm speichert einen String im Off-Heap-Memory, ruft f\u00fcr diesen die \"strlen\"-Funktion der C-Standard-Library auf und gibt das Ergebnis auf der Konsole aus:<\/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> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FFMTest20<\/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.openConfined()) {\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-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>Um das Programm mit Java 20 zu compilieren und zu starten, musst du folgende Parameter mit angeben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ javac --enable-preview --source 20 FFMTest20.java\n$ java --enable-preview --enable-native-access=ALL-UNNAMED FFMTest20 \n\nlen = 13\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><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>Da die meisten Java-Entwicklerinnen und -Entwickler eher selten mit der Foreign Function &amp; Memory API in Ber\u00fchrung kommen werden, werde ich an dieser Stelle nicht tiefer in die Materie einsteigen. Interessierte finden weitere Details in <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/434\" target=\"_blank\">JEP 434<\/a> und auf der Seite von <a href=\"https:\/\/openjdk.org\/projects\/panama\/\" target=\"_blank\" rel=\"noopener\">Project Panama<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"virtual-threads-second-preview-jep-436\">Virtual Threads (Second Preview) \u2013 JEP 436<\/h3>\n\n\n\n<p>Virtuelle Threads wurden in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-19-features\/#Virtual_Threads_Preview_-_JEP_425\">Java 19<\/a> erstmals als Incubator Feature vorgestellt. Virtuelle Threads sind leichtgewichtige Threads, die keine Betriebssystem-Threads blockieren, wenn sie z. B. auf Locks, blockierende Datenstrukturen oder Antworten von externen System warten m\u00fcssen.<\/p>\n\n\n\n<p>Alles \u00fcber virtuelle Threads erf\u00e4hrst du im <a href=\"https:\/\/www.happycoders.eu\/de\/java\/virtual-threads\/\">Hauptartikel \u00fcber virtuelle Threads<\/a>.<\/p>\n\n\n\n<p>Mit <a href=\"https:\/\/openjdk.org\/jeps\/436\">JDK Enhancement Proposal 436<\/a> werden virtuelle Threads zur weiteren Sammlung von Feedback ohne \u00c4nderungen in einer zweiten Preview-Phase wiedervorgelegt.<\/p>\n\n\n\n<p>Es wurden lediglich einige \u00c4nderungen aus dem ersten Preview, die nicht spezifisch f\u00fcr virtuelle Threads waren und bereits in Java 19 finalisiert wurden, nicht mehr explizit im aktuellen JEP aufgef\u00fchrt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Neue Methoden in <code>Thread<\/code>: <code>join(Duration)<\/code>, <code>sleep(Duration)<\/code> und <code>threadId()<\/code>.<\/li>\n\n\n\n<li>Neue Methoden in Future: <code>resultNow()<\/code>, <code>exceptionNow()<\/code> und <code>state()<\/code>.<\/li>\n\n\n\n<li><code>ExecutorService<\/code> erweitert das <code>AutoCloseable<\/code>-Interface.<\/li>\n\n\n\n<li>Die <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-19-features\/#javalangThreadGroup_is_degraded\">Au\u00dferbetriebsetzung zahlreicher <code>ThreadGroup<\/code>-Methoden<\/a>.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"structured-concurrency-second-incubator-jep-437\">Structured Concurrency (Second Incubator) \u2013 JEP 437<\/h3>\n\n\n\n<p>Genau wie virtuelle Threads wurde auch \"Structured Concurrency\" erstmals in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-19-features\/#Structured_Concurrency_Incubator_-_JEP_428\">Java 19<\/a> vorgestellt und in Java 20 mit <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/jeps\/437\" target=\"_blank\">JDK Enhancement Proposal 437<\/a> wiedervorgelegt.<\/p>\n\n\n\n<p>Wenn eine Aufgabe aus mehreren Teilaufgaben besteht, die parallel abgearbeitet werden k\u00f6nnen, erlaubt Structured Concurrency es uns, dies auf eine Art und Weise zu implementieren, die besonders gut les- und wartbar ist.<\/p>\n\n\n\n<p>Wie das genau funktioniert, kannst du im <a href=\"\/de\/java\/structured-concurrency-structuredtaskscope\/\">Hauptartikel \u00fcber Structured Concurrency<\/a> nachlesen.<\/p>\n\n\n\n<p>In der zweiten Incubator-Phase wird <code>StructuredTaskScope<\/code> dahingehend erweitert, dass es die ebenfalls in Java 20 eingef\u00fchrten \"Scoped Values\" automatisch an alle Kind-Threads weitervererbt.<\/p>\n\n\n\n<p>Wie das funktioniert, liest du im Abschnitt <a href=\"\/de\/java\/structured-concurrency-structuredtaskscope\/#structuredtaskscope-und-scoped-values\">StructuredTaskScope und Scoped Values<\/a> im o. g. Artikel.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecations-und-loeschungen\">Deprecations und L\u00f6schungen<\/h2>\n\n\n\n<p>In Java 20 wurden einige Methoden als \"deprecated\" markiert bzw. komplett au\u00dfer Betrieb gesetzt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"java-net-url-constructors-are-deprecated\">java.net.URL constructors are deprecated<\/h3>\n\n\n\n<p>Die Konstruktoren von <code>java.net.URL<\/code> wurden als \"deprecated\" markiert. Stattdessen sollen die Methoden <code>URI.create(...)<\/code> und <code>URI.toURL()<\/code> verwendet werden. Hier ein Beispiel:<\/p>\n\n\n\n<p>Alter Code:<\/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\">URL url = <span class=\"hljs-keyword\">new<\/span> URL(<span class=\"hljs-string\">\"https:\/\/www.happycoders.eu\"<\/span>);<\/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>Neuer Code:<\/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\">URL url = URI.create(<span class=\"hljs-string\">\"https:\/\/www.happycoders.eu\"<\/span>).toURL();<\/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>F\u00fcr diese \u00c4nderung existiert kein JDK Enhancement Proposal.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"thread-suspend-resume-changed-to-throw-unsupportedoperationexception\">Thread.suspend\/resume changed to throw UnsupportedOperationException<\/h3>\n\n\n\n<p><code>Thread.suspend()<\/code> und <code>resume()<\/code> wurden bereits in Java 1.2 als \"deprecated\" markiert, da die Methoden anf\u00e4llig f\u00fcr Deadlocks sind. In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-14-features\/#Thread_SuspendResume_Are_Deprecated_for_Removal\">Java 14<\/a> wurden die Methoden als \"deprecated for removal\" markiert. <\/p>\n\n\n\n<p>Ab Java 20 werfen beide Methoden eine <code>UnsupportedOperationException<\/code>.<\/p>\n\n\n\n<p>F\u00fcr diese \u00c4nderung existiert kein JDK Enhancement Proposal.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"thread-stop-changed-to-throw-unsupportedoperationexception\">Thread.stop changed to throw UnsupportedOperationException<\/h3>\n\n\n\n<p>Auch das von Natur aus unsichere, da zu unvorhersehbarem Verhalten f\u00fchrende <code>Thread.stop()<\/code> wurde in Java 1.2 als \"deprecated\" markiert und in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-18-features\/#terminally-deprecate-thread-stop\">Java 18<\/a> als \"deprecated for removal\".<\/p>\n\n\n\n<p>Auch diese Methode wirft nun eine <code>UnsupportedOperationException<\/code>.<\/p>\n\n\n\n<p>F\u00fcr diese \u00c4nderung existiert kein JDK Enhancement Proposal.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-20\">Sonstige \u00c4nderungen in Java 20<\/h2>\n\n\n\n<p>In diesem Abschnitt findest du einige von mir ausgew\u00e4hlte kleinere \u00c4nderungen in Java 20, f\u00fcr die es keine JDK Enhancements Proposals gibt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"javac-warns-about-type-casts-in-compound-assignments-with-possible-lossy-conversions\">Javac Warns about Type Casts in Compound Assignments with Possible Lossy Conversions<\/h3>\n\n\n\n<p>Ich halte es f\u00fcr wichtig, diese scheinbar kleine \u00c4nderung hier prominent zu erw\u00e4hnen. Denn viele Java-Entwickler kennen eine Besonderheit der sogenannten \"Compound Assignment Operators\" (<code>+=<\/code>, <code>*=<\/code>, usw.) nicht. Das kann zu unerwarteten Fehlern f\u00fchren.<\/p>\n\n\n\n<p>Was ist der Unterschied zwischen den folgenden Operationen?<\/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\">a += b;\na = a + b;<\/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>Die meisten Java-Entwickler werden sagen: Es gibt keinen.<\/p>\n\n\n\n<p>Doch das ist falsch.<\/p>\n\n\n\n<p>Wenn z. B. <code>a<\/code> ein <code>short<\/code> ist und <code>b<\/code> ein <code>int<\/code>, dann f\u00fchrt die zweite Zeile zu einem Compilerfehler:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">java: incompatible types: possible lossy conversion from int to short<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><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>Denn <code>a + b<\/code> ergibt ein <code>int<\/code>, welches ohne expliziten Cast nicht der <code>short<\/code>-Variablen <code>a<\/code> zugewiesen werden kann.<\/p>\n\n\n\n<p>Die erste Zeile hingegen ist erlaubt, da der Compiler bei einem Compound Assignment einen impliziten Cast einf\u00fcgt. Wenn <code>a<\/code> ein <code>short<\/code> ist, dann ist <code>a += b<\/code> \u00e4quivalent zu:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">a = (<span class=\"hljs-keyword\">short<\/span>) (a + b);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><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 einem Cast von <code>int<\/code> auf <code>short<\/code> werden die linken 16 Bit abgeschnitten. Es gehen also Informationen verloren, wie folgendes Beispiel zeigt:<\/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\"><span class=\"hljs-keyword\">short<\/span> a = <span class=\"hljs-number\">30_000<\/span>;\n<span class=\"hljs-keyword\">int<\/span> b = <span class=\"hljs-number\">50_000<\/span>;\na += b;\nSystem.out.println(<span class=\"hljs-string\">\"a = \"<\/span> + a);<\/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>Das Programm gibt nicht 80000 (hexadezimal 0x13880) aus, sondern 14464 (hexadezimal 0x3880).<\/p>\n\n\n\n<p>Um Entwickler vor diesem potentiell unerw\u00fcnschten Verhalten zu warnen, wurde in Java 20 (endlich!) eine entsprechende Compiler-Warnung eingef\u00fchrt.<\/p>\n\n\n\n<p>F\u00fcr diese Erweiterung gibt es kein JDK Enhancement Proposal.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"idle-connection-timeouts-for-http-2\">Idle Connection Timeouts for HTTP\/2<\/h3>\n\n\n\n<p>\u00dcber die System Property <code>jdk.httpclient.keepalive.timeout<\/code> kann eingestellt werden, wie lange inaktive HTTP\/1.1-Verbindungen offen gehalten werden.<\/p>\n\n\n\n<p>Ab Java 20 gilt diese Eigenschaft auch f\u00fcr HTTP\/2-Verbindungen.<\/p>\n\n\n\n<p>Desweiteren wurde die System Property <code>jdk.httpclient.keepalive.timeout.h2<\/code> hinzugef\u00fcgt, mit der dieser Wert speziell f\u00fcr HTTP\/2-Verbindungen \u00fcberschrieben werden kann.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"httpclient-default-keep-alive-time-is-30-seconds\">HttpClient Default Keep Alive Time is 30 Seconds<\/h3>\n\n\n\n<p>Wird die eben genannte System Property <code>jdk.httpclient.keepalive.timeout<\/code> nicht definiert, galt bis Java 19 ein Standardwert von 1.200 Sekunden. In Java 20 wurde der Standardwert auf 30 Sekunden herabgesetzt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"identityhashmaps-remove-and-replace-methods-use-object-identity\">IdentityHashMap's Remove and Replace Methods Use Object Identity<\/h3>\n\n\n\n<p><code>IdentityHashMap<\/code> ist eine spezielle Map-Implementierung, bei der Keys nicht dann als gleich gelten, wenn die <code>equals()<\/code>-Methode <code>true<\/code> ergibt, sondern dann, wenn die Key-Objekte identisch sind, also der Vergleich mittels <code>==<\/code>-Operator <code>true<\/code> ergibt.<\/p>\n\n\n\n<p>Als in Java 8 dem <code>Map<\/code>-Interface die Default-Methoden <code>remove(Object key, Object value)<\/code> und <code>replace(K key, V oldValue, V newValue)<\/code> hinzugef\u00fcgt wurden, wurde allerdings vergessen diese Methoden in <code>IdentityHashMap<\/code> so zu \u00fcberschreiben, dass sie <code>==<\/code> anstelle von <code>equals()<\/code> verwenden.<\/p>\n\n\n\n<p>Dieser Fehler wurde nun korrigiert \u2013 nach achteinhalb Jahren. Dass der Bug so lange nicht aufgefallen ist, ist ein Zeichen daf\u00fcr, dass <code>IdentityHashMap<\/code> allgemein wenig genutzt wird (und m\u00f6glicherweise weitere Bugs enth\u00e4lt).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"support-unicode-15-0\">Support Unicode 15.0<\/h3>\n\n\n\n<p>Der Unicode-Support wird in Java 20 auf Version 15.0 angehoben. Relevant ist das u. a. f\u00fcr die Klassen <code>String<\/code> und <code>Character<\/code>, die mit den neuen Zeichen, Codebl\u00f6cken und Schriftsystemen umgehen k\u00f6nnen m\u00fcssen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-20\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 20<\/h3>\n\n\n\n<p>Neben den oben aufgelisteten JEPs und sonstigen \u00c4nderungen enth\u00e4lt auch Java 20 zahlreiche kleinere \u00c4nderungen, die den Rahmen dieses Artikels sprengen w\u00fcrden. Eine vollst\u00e4ndige Liste findest du in den <a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/20all-relnotes.html\" target=\"_blank\" rel=\"noreferrer noopener\">Java 20 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>Mit \"Scoped Values\" erhalten wir in Java 20 ein sehr n\u00fctzliches Konstrukt, um einem Thread und ggf. einer Gruppe von Kind-Threads f\u00fcr deren Lebensdauer einen nur lesbaren, Thread-spezifischen Wert zur Verf\u00fcgung zu stellen.<\/p>\n\n\n\n<p>Alle anderen JEPs sind minimal (oder gar nicht) ver\u00e4nderte Wiedervorlagen vorangegangener JEPs.<\/p>\n\n\n\n<p>Das aktuelle Java 20 Release kannst du <a rel=\"noopener\" href=\"https:\/\/jdk.java.net\/20\/\" target=\"_blank\">hier<\/a> herunterladen.<\/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 20 Features mit Beispielen: Scoped Values (Incubator), Record Patterns (Second Preview), Pattern Matching for switch (Fourth Preview), Foreign Function &#038; Memory API (Second Preview), Virtual Threads (Second Preview), Structured Concurrency (Second Incubator)<\/p>\n","protected":false},"author":1,"featured_media":34250,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"Die neuen Java 20 Features mit Beispielen: Scoped Values, Record Patterns, Pattern Matching for switch, Virtual Threads, Structured Concurrency","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"java 20,java 20 features","_seopress_news_disabled":"","_seopress_video_disabled":"","_seopress_video":[],"_seopress_pro_schemas_manual":[],"_seopress_pro_rich_snippets_disable_all":"","_seopress_pro_rich_snippets_disable":[],"_seopress_pro_schemas":[],"_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":21704,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-33905","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\/2022\/12\/java-20-features.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/java-20-features.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":0,"uagb_excerpt":"Die neuen Java 20 Features mit Beispielen: Scoped Values (Incubator), Record Patterns (Second Preview), Pattern Matching for switch (Fourth Preview), Foreign Function & Memory API (Second Preview), Virtual Threads (Second Preview), Structured Concurrency (Second Incubator)","public_identification_id":"21b0316d843047b1a234b121eccee51a","private_identification_id":"e80449a1c3fd4d25b5509e96ac2a6598","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/33905","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=33905"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/33905\/revisions"}],"predecessor-version":[{"id":53957,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/33905\/revisions\/53957"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34250"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=33905"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=33905"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=33905"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}