{"id":40593,"date":"2024-06-06T01:00:00","date_gmt":"2024-06-05T23:00:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=40593"},"modified":"2025-12-05T08:10:15","modified_gmt":"2025-12-05T07:10:15","slug":"java-23-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-23-features\/","title":{"rendered":"Java 23 Features (mit Beispielen)"},"content":{"rendered":"\n<p>Java 23 wurde am 17. September 2024 ver\u00f6ffentlicht. Du kannst es <a href=\"https:\/\/jdk.java.net\/23\/\" target=\"_blank\" rel=\"noopener\">hier<\/a> herunterladen.<\/p>\n\n\n\n<p>Die Highlights von Java 23:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#markdown-documentation-comments-jep-467\">Markdown Documentation Comments<\/a>: Endlich d\u00fcrfen wir JavaDoc auch mit Markdown schreiben.<\/li>\n\n\n\n<li>Importiere ganze Module mit <a href=\"#module-import-declarations-preview-jep-476\">Module Import Declarations<\/a>.<\/li>\n\n\n\n<li>Matche Variablen jetzt auch gegen <em>primitive<\/em> Typen mit <a href=\"#primitive-types-in-patterns-instanceof-and-switch-preview-jep-455\">Primitive Types in Patterns, instanceof, and switch (Preview)<\/a>.<\/li>\n\n\n\n<li><code>print()<\/code>, <code>println()<\/code> und <code>readln()<\/code>: Ein- und Ausgaben ohne <code>System.in<\/code> und <code>System.out<\/code> mit <a href=\"#implicitly-declared-classes-and-instance-main-methods-third-preview-jep-477\">Implicitly Declared Classes and Instance Main Methods<\/a>.<\/li>\n\n\n\n<li>Benutze <a href=\"#flexible-constructor-bodies-second-preview-jep-482\">Flexible Constructor Bodies<\/a>, um in Konstruktoren schon <em>vor<\/em> dem Aufruf von <code>super(...)<\/code> Felder zu initialisieren.<\/li>\n<\/ul>\n\n\n\n<p>Dar\u00fcber hinaus gehen viele weitere in <a href=\"\/de\/java\/java-21-features\/\">Java 21<\/a> und <a href=\"\/de\/java\/java-22-features\/\">Java 22<\/a> eingef\u00fchrte Features ohne bzw. mit kleinen \u00c4nderungen in eine neue Preview-Runde.<\/p>\n\n\n\n<p>Eine Ausnahme machen die in Java 21 vorgestellten und in Java 22 wiedervorgelegten <a href=\"\/de\/java\/string-templates\/\">String Templates<\/a>: Diese sind in Java 23 nicht mehr enthalten. <a href=\"https:\/\/mail.openjdk.org\/pipermail\/amber-spec-experts\/2024-April\/004106.html\" target=\"_blank\" rel=\"noopener\">Laut Gavin Bierman<\/a> besteht zwar Einigkeit dar\u00fcber, dass das Design \u00fcberarbeitet werden muss, jedoch herrscht Uneinigkeit dar\u00fcber, wie dies konkret geschehen soll. Die Sprachentwickler haben daher beschlossen, sich mehr Zeit f\u00fcr die \u00dcberarbeitung des Designs zu nehmen und das Feature in einer sp\u00e4teren Java-Version rundum \u00fcberarbeitet vorzustellen.<\/p>\n\n\n\n<p>F\u00fcr alle JEPs und sonstigen \u00c4nderungen verwende ich wie immer die originalen, englischen Bezeichnungen.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"markdown-documentation-comments-jep-467\">Markdown Documentation Comments \u2013 JEP 467<\/h2>\n\n\n\n<p>Um JavaDoc-Kommentare zu formatieren, mussten wir seit jeher HTML verwenden. Das war 1995 sicher eine gute Wahl \u2013 heutzutage ist jedoch f\u00fcr das Schreiben von Dokumentation Markdown wesentlich beliebter als HTML.<\/p>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/467\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 467<\/a> macht es m\u00f6glich, dass wir ab Java 23 JavaDoc-Kommentare zuk\u00fcnftig in Markdown schreiben k\u00f6nnen.<\/p>\n\n\n\n<p>Das folgende Beispiel zeigt die Dokumentation der <code>Math.ceilMod(...)<\/code>-Methode in der herk\u00f6mmlichen Schreibweise:<\/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-comment\">\/**\n * Returns the ceiling modulus of the {<span class=\"hljs-doctag\">@code<\/span> long} and {<span class=\"hljs-doctag\">@code<\/span> int} arguments.\n * &lt;p&gt;\n * The ceiling modulus is {<span class=\"hljs-doctag\">@code<\/span> r = x - (ceilDiv(x, y) * y)},\n * has the opposite sign as the divisor {<span class=\"hljs-doctag\">@code<\/span> y} or is zero, and\n * is in the range of {<span class=\"hljs-doctag\">@code<\/span> -abs(y) &lt; r &lt; +abs(y)}.\n *\n * &lt;p&gt;\n * The relationship between {<span class=\"hljs-doctag\">@code<\/span> ceilDiv} and {<span class=\"hljs-doctag\">@code<\/span> ceilMod} is such that:\n * &lt;ul&gt;\n *   &lt;li&gt;{<span class=\"hljs-doctag\">@code<\/span> ceilDiv(x, y) * y + ceilMod(x, y) == x}&lt;\/li&gt;\n * &lt;\/ul&gt;\n * &lt;p&gt;\n * For examples, see {<span class=\"hljs-doctag\">@link<\/span> #ceilMod(int, int)}.\n *\n * <span class=\"hljs-doctag\">@param<\/span> x the dividend\n * <span class=\"hljs-doctag\">@param<\/span> y the divisor\n * <span class=\"hljs-doctag\">@return<\/span> the ceiling modulus {<span class=\"hljs-doctag\">@code<\/span> x - (ceilDiv(x, y) * y)}\n * <span class=\"hljs-doctag\">@throws<\/span> ArithmeticException if the divisor {<span class=\"hljs-doctag\">@code<\/span> y} is zero\n * <span class=\"hljs-doctag\">@see<\/span> #ceilDiv(long, int)\n * <span class=\"hljs-doctag\">@since<\/span> 18\n *\/<\/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>Das Beispiel enth\u00e4lt formatierten Code, Absatzmarken, eine Aufz\u00e4hlung, einen Link und JavaDoc-spezifische Angaben wie <code>@param<\/code> und <code>@return<\/code>.<\/p>\n\n\n\n<p>Um Markdown zu verwenden, m\u00fcssen wir alle Zeilen eines JavaDoc-Kommentars mit drei Schr\u00e4gstrichen beginnen lassen. Derselbe Kommentar als Markdown w\u00fcrde wie folgt aussehen:<\/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-comment\">\/\/\/ Returns the ceiling modulus of the `long` and `int` arguments.<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ The ceiling modulus is `r = x - (ceilDiv(x, y) * y)`,<\/span>\n<span class=\"hljs-comment\">\/\/\/ has the opposite sign as the divisor `y` or is zero, and<\/span>\n<span class=\"hljs-comment\">\/\/\/ is in the range of `-abs(y) &lt; r &lt; +abs(y)`.<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ The relationship between `ceilDiv` and `ceilMod` is such that:<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ - `ceilDiv(x, y) * y + ceilMod(x, y) == x`<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ For examples, see &#091;#ceilMod(int, int)].<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ @param x the dividend<\/span>\n<span class=\"hljs-comment\">\/\/\/ @param y the divisor<\/span>\n<span class=\"hljs-comment\">\/\/\/ @return the ceiling modulus `x - (ceilDiv(x, y) * y)`<\/span>\n<span class=\"hljs-comment\">\/\/\/ @throws ArithmeticException if the divisor `y` is zero<\/span>\n<span class=\"hljs-comment\">\/\/\/ @see #ceilDiv(long, int)<\/span>\n<span class=\"hljs-comment\">\/\/\/ @since 18<\/span><\/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>Das ist sowohl einfacher zu schreiben als auch besser zu lesen.<\/p>\n\n\n\n<p>Was hat sich im Einzelnen ver\u00e4ndert?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Statt mit <code>{@code ... }<\/code> wird Quellcode mit <code>`...`<\/code> markiert.<\/li>\n\n\n\n<li>Das HTML-Absatzzeichen <code>&lt;p&gt;<\/code> kann durch eine Leerzeile ersetzt werden.<\/li>\n\n\n\n<li>Die Elemente der Aufz\u00e4hlung werden durch Bindestriche eingeleitet.<\/li>\n\n\n\n<li>Statt mit <code>{@link ... }<\/code> werden Links mit <code>[...]<\/code> markiert.<\/li>\n\n\n\n<li>Die JavaDoc-spezifische Angaben wie <code>@param<\/code> und <code>@return<\/code> bleiben unver\u00e4ndert.<\/li>\n<\/ul>\n\n\n\n<p>Die folgenden Text-Formatierungen werden unterst\u00fctzt:<\/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-comment\">\/\/\/ **This text is bold.**<\/span>\n<span class=\"hljs-comment\">\/\/\/ *This text is italic.*<\/span>\n<span class=\"hljs-comment\">\/\/\/ _This is also italic._<\/span>\n<span class=\"hljs-comment\">\/\/\/ `This is source code.`<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ ```<\/span>\n<span class=\"hljs-comment\">\/\/\/ This is a block of source codex.<\/span>\n<span class=\"hljs-comment\">\/\/\/ ```<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/     Indented text<\/span>\n<span class=\"hljs-comment\">\/\/\/     is also rendered as a code block.<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ ~~~<\/span>\n<span class=\"hljs-comment\">\/\/\/ This is also a block of source code<\/span>\n<span class=\"hljs-comment\">\/\/\/ ~~~<\/span><\/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>Aufz\u00e4hlungslisten und nummerierte Listen werden unterst\u00fctzt:<\/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-comment\">\/\/\/ This is a bulleted list:<\/span>\n<span class=\"hljs-comment\">\/\/\/ - One<\/span>\n<span class=\"hljs-comment\">\/\/\/ - Two<\/span>\n<span class=\"hljs-comment\">\/\/\/ - Three<\/span>\n<span class=\"hljs-comment\">\/\/\/<\/span>\n<span class=\"hljs-comment\">\/\/\/ This is a numbered list:<\/span>\n<span class=\"hljs-comment\">\/\/\/ 1. One<\/span>\n<span class=\"hljs-comment\">\/\/\/ 1. Two<\/span>\n<span class=\"hljs-comment\">\/\/\/ 1. Three<\/span><\/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>Auch einfache Tabellen k\u00f6nnen dargestellt werden:<\/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-comment\">\/\/\/ | Binary | Decimal |<\/span>\n<span class=\"hljs-comment\">\/\/\/ |--------|---------|<\/span>\n<span class=\"hljs-comment\">\/\/\/ |     00 |       0 |<\/span>\n<span class=\"hljs-comment\">\/\/\/ |     01 |       1 |<\/span>\n<span class=\"hljs-comment\">\/\/\/ |     10 |       2 |<\/span>\n<span class=\"hljs-comment\">\/\/\/ |     11 |       3 |<\/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>Links zu anderen Programmelementen k\u00f6nnen wie folgt eingebaut werden:<\/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-comment\">\/\/\/ Links:<\/span>\n<span class=\"hljs-comment\">\/\/\/ - ein Modul: &#091;java.base\/]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - ein Paket: &#091;java.lang]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - eine Klasse: &#091;Integer]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - ein Feld: &#091;Integer#MAX_VALUE]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - eine Methode: &#091;Integer#parseInt(String, int)]<\/span><\/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>Sollen sich Link-Text und Link-Ziel unterscheiden, kann der Link-Text in eckigen Klammern vorangestellt werden:<\/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-comment\">\/\/\/ Links:<\/span>\n<span class=\"hljs-comment\">\/\/\/ - &#091;ein Modul]&#091;java.base\/]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - &#091;ein Paket]&#091;java.lang]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - &#091;eine Klasse]&#091;Integer]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - &#091;ein Feld]&#091;Integer#MAX_VALUE]<\/span>\n<span class=\"hljs-comment\">\/\/\/ - &#091;eine Methode]&#091;Integer#parseInt(String)]<\/span><\/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>Und zu guter Letzt: JavaDoc-Tags wie <code>@param<\/code>, <code>@throws<\/code> etc. werden nicht ausgewertet, wenn sie innerhalb von Code oder Code-Bl\u00f6cken verwendet werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"neue-preview-features-in-java-23\">Neue Preview-Features in Java 23<\/h2>\n\n\n\n<p>Java 23 bringt uns zwei neue Preview-Features. Diese solltest du nicht in Produktivcode einsetzen, da sie sich noch \u00e4ndern k\u00f6nnen (oder, wie im Fall von String Templates, auch kurzfristig wieder entfernt werden k\u00f6nnen).<\/p>\n\n\n\n<p>Du musst Preview-Features sowohl im <code>javac<\/code>-Kommando explizit \u00fcber die VM-Optionen <code>--enable-preview --source 23 <\/code>freischalten. F\u00fcr das <code>java<\/code>-Kommando gen\u00fcgt <code>--enable-preview<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"module-import-declarations-preview-jep-476\">Module Import Declarations (Preview) \u2013 JEP 476<\/h3>\n\n\n\n<p>Schon seit Java 1.0 werden in jeder <em>.java<\/em>-Datei automatisch alle Klassen des Pakets <code>java.lang<\/code> importert. Deshalb k\u00f6nnen wir Klassen wie <code>Object<\/code>, <code>String<\/code>, <code>Integer<\/code>, <code>Exception<\/code>, <code>Thread<\/code>, usw. ohne <code>import<\/code>-Statements verwenden.<\/p>\n\n\n\n<p>Ebenso konnten wir schon immer komplette Pakete importieren. So f\u00fchrt z. B. <code>import java.util.*<\/code> dazu, dass wir Klassen wie <code>List<\/code>, <code>Set<\/code>, <code>Map<\/code>, <code>ArrayList<\/code>, <code>HashSet<\/code> und <code>HashMap<\/code> nicht einzeln importieren m\u00fcssen.<\/p>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/476\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 476<\/a> macht es nun m\u00f6glich, dass wir auch komplette <em>Module<\/em> importieren k\u00f6nnen. Genauer gesagt: alle Klassen in den vom Modul exportierten Paketen.<\/p>\n\n\n\n<p>So k\u00f6nnen wir z. B. wie folgt das komplette <code>java.base<\/code>-Modul importieren und Klassen dieses Moduls (im Beispiel <code>List<\/code>, <code>Map<\/code>, <code>Collectors<\/code>, <code>Stream<\/code>) ohne weitere Imports nutzen:<\/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-keyword\">import<\/span> <span class=\"hljs-keyword\">module<\/span> java.base;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> Map&lt;Character, List&lt;String&gt;&gt; groupByFirstLetter(String... values) {\n  <span class=\"hljs-keyword\">return<\/span> Stream.of(values).collect(\n      Collectors.groupingBy(s -&gt; Character.toUpperCase(s.charAt(<span class=\"hljs-number\">0<\/span>))));\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>Um <code>import module<\/code> zu verwenden ist es nicht n\u00f6tig, dass sich die importierende Klasse selbst in einem Modul befindet.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Mehrdeutige Klassennamen<\/h4>\n\n\n\n<p>Wenn es zwei importierte Klassen mit gleichem Namen gibt, wie <code>Date<\/code> im folgenden Beispiel, kommt es zu einem Compiler-Fehler:<\/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\">import<\/span> <span class=\"hljs-keyword\">module<\/span> java.base;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-keyword\">module<\/span> java.sql;\n\n. . .\nDate date = <span class=\"hljs-keyword\">new<\/span> Date();  <span class=\"hljs-comment\">\/\/ Compiler error: \"reference to Date is ambiguous\"<\/span>\n. . .<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die L\u00f6sung ist einfach: Wir m\u00fcssen die gew\u00fcnschte <code>Date<\/code>-Klasse zus\u00e4tzlich direkt importieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-keyword\">module<\/span> java.base;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-keyword\">module<\/span> java.sql;\n<span class=\"hljs-keyword\">import<\/span> java.util.Date;  <span class=\"hljs-comment\">\/\/ \u27f5 This resolves the ambiguity<\/span>\n\n. . .\nDate date = <span class=\"hljs-keyword\">new<\/span> Date();\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<h4 class=\"wp-block-heading\">Transitive Imports<\/h4>\n\n\n\n<p>Wenn ein importiertes Modul ein anderes Modul <em>transitiv<\/em> importiert, dann sind auch alle Klassen der exportierten Pakete des transitiv importierten Moduls ohne explizite Imports nutzbar.<\/p>\n\n\n\n<p>Beispielsweise importiert das Modul <code>java.sql<\/code> das Module <code>java.xml<\/code> transitiv:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">module<\/span> java.sql {\n  . . .\n  <span class=\"hljs-keyword\">requires<\/span> transitive java.xml;\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>Somit ben\u00f6tigen wir im folgenden Beispiel keine expliziten Imports f\u00fcr <code>SAXParserFactory<\/code> und <code>SAXParser<\/code> und auch keinen expliziten Import des Moduls <code>java.xml<\/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\">import<\/span> <span class=\"hljs-keyword\">module<\/span> java.sql;\n\n. . .\nSAXParserFactory factory = SAXParserFactory.newInstance();\nSAXParser saxParser = factory.newSAXParser();\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<h4 class=\"wp-block-heading\">Automatischer Modul-Import in JShell<\/h4>\n\n\n\n<p><em>JShell<\/em> importiert automatisch zehn h\u00e4ufig genutzte Pakete. Durch diesen JEP wird <em>JShell<\/em> in Zukunft das komplette <code>java.base<\/code>-Modul importieren.<\/p>\n\n\n\n<p>Das l\u00e4sst sich sehr sch\u00f6n demonstrieren, indem man <em>JShell<\/em> einmal ohne und einmal mit <code>--enable-preview<\/code> aufruft und dann das Kommando <code>\/imports<\/code> eingibt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ jshell\n|  Welcome to JShell -- Version 23-ea\n|  For an introduction type: \/help intro\n\njshell&gt; \/imports\n|    import java.io.*\n|    import java.math.*\n|    import java.net.*\n|    import java.nio.file.*\n|    import java.util.*\n|    import java.util.concurrent.*\n|    import java.util.function.*\n|    import java.util.prefs.*\n|    import java.util.regex.*\n|    import java.util.stream.*\n\njshell&gt; \/exit\n|  Goodbye\n\n$ jshell --enable-preview\n|  Welcome to JShell -- Version 23-ea\n|  For an introduction type: \/help intro\n\njshell&gt; \/imports\n|    import java.base<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><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>Beim Aufruf ohne <code>--enable-preview<\/code> sieht du die zehn importieren Pakete, beim Aufruf mit <code>--enable-preview<\/code> siehst du nur den Import des <code>java.base<\/code>-Moduls.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Automatischer Modul-Import in implizit deklarierten Klassen <\/h4>\n\n\n\n<p><a href=\"\/de\/java\/main-methode\/#implizit-deklarierte-klassen\">Implizit deklarierte Klassen<\/a> importieren ab Java 23 ebenfalls automatisch das komplette <code>java.base<\/code>-Modul.<\/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=\"primitive-types-in-patterns-instanceof-and-switch-preview-jep-455\">Primitive Types in Patterns, instanceof, and switch (Preview) \u2013 JEP 455<\/h3>\n\n\n\n<p>Mit <code>instanceof<\/code> und <code>switch<\/code> k\u00f6nnen wir \u00fcberpr\u00fcfen, ob ein Objekt von einem bestimmten Typ ist, und wenn ja, dieses Objekt an eine Variable dieses Typs binden, einen bestimmten Programmpfad ausf\u00fchren und in diesem Programmpfad die neue Variable benutzen.<\/p>\n\n\n\n<p>Der folgende, seit <a href=\"\/de\/java\/java-16-features\/#Pattern_Matching_for_instanceof\">Java 16<\/a> erlaubte Codeblock z. B. pr\u00fcft, ob ein Objekt ein mindestens f\u00fcnf Zeichen langer String ist, und wenn ja, gibt er diesen in Gro\u00dfbuchstaben aus. Wenn das Objekt ein Integer ist, wird die Zahl quadriert und ausgegeben. Andernfalls wird das Objekt ausgegeben, wie es ist.<\/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\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s &amp;&amp; s.length() &gt;= <span class=\"hljs-number\">5<\/span>) {\n  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> Integer i) {\n  System.out.println(i * i);\n} <span class=\"hljs-keyword\">else<\/span> {\n  System.out.println(obj);\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>Das gleiche k\u00f6nnen wir seit <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-21-features\/#Pattern_Matching_for_switch_JEP_441\">Java 21<\/a> deutlich \u00fcbersichtlicher mit <code>switch<\/code> machen:<\/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-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> Integer i                     -&gt; System.out.println(i * i);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">null<\/span>, <span class=\"hljs-keyword\">default<\/span>                 -&gt; System.out.println(obj);\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>Das funktioniert bisher aber nur mit Objekten. <code>instanceof<\/code> kann bisher gar nicht mit primitiven Datentypen kombiniert werden, <code>switch<\/code> nur insoweit, dass es Variablen der primitiven Typen <code>byte<\/code>, <code>short<\/code>, <code>char<\/code> und <code>int<\/code> gegen Konstanten matchen kann, z. B. so:<\/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\">int<\/span> x = ...\n<span class=\"hljs-keyword\">switch<\/span> (x) {\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span> -&gt; System.out.println(<span class=\"hljs-string\">\"Low\"<\/span>);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">6<\/span> -&gt; System.out.println(<span class=\"hljs-string\">\"Medium\"<\/span>);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">8<\/span>, <span class=\"hljs-number\">9<\/span> -&gt; System.out.println(<span class=\"hljs-string\">\"High\"<\/span>);\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>Durch <a href=\"https:\/\/openjdk.org\/jeps\/455\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 455<\/a> gibt es in Java 23 zwei \u00c4nderungen:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Zum einen d\u00fcrfen in <code>switch<\/code>-Ausdr\u00fccken und -Anweisungen ab sofort <em>alle<\/em> primitiven Typen verwendet werden, also auch <code>long<\/code>, <code>float<\/code>, <code>double<\/code> und <code>boolean<\/code>.<\/li>\n\n\n\n<li>Zum anderen k\u00f6nnen wir auch alle primitiven Typen im Pattern Matching verwenden \u2013 sowohl bei <code>instanceof<\/code> als auch bei <code>switch<\/code>.<\/li>\n<\/ol>\n\n\n\n<p>In beiden F\u00e4llen, also bei <code>switch<\/code> \u00fcber <code>long<\/code>, <code>float<\/code>, <code>double<\/code> und <code>boolean<\/code> sowie beim Pattern Matching mit primitiven Variablen, muss der <code>switch<\/code> \u2013 genauso wie bei allen neuen <code>switch<\/code>-Features \u2013 ersch\u00f6pfend sein, also alle m\u00f6glichen F\u00e4lle abdecken.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Ab Java 23: Primitive Typen im Pattern Matching<\/h4>\n\n\n\n<p>Bei primitiven Pattern ist die genaue Bedeutung eine andere als bei der Verwendung von Objekten \u2013 denn bei primitiven Typen gibt es ja keine Vererbung:<\/p>\n\n\n\n<p>Sei <code>a<\/code> eine Variable eines primitiven Typen (also <code>byte<\/code>, <code>short<\/code>, <code>int<\/code>, <code>long<\/code>, <code>float<\/code>, <code>double<\/code>, <code>char<\/code> oder <code>boolean<\/code>) und <code>B<\/code> einer eben dieser primitiven Typen. Dann ergibt <code>a instanceof B<\/code> genau dann <code>true<\/code>, wenn der pr\u00e4zise Wert von <code>a<\/code> auch in einer Variablen vom Typ <code>B<\/code> gespeichert werden kann.<\/p>\n\n\n\n<p>Damit du besser verstehst, was damit gemeint ist, hier ein einfaches 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\"><span class=\"hljs-keyword\">int<\/span> a = ...\n<span class=\"hljs-keyword\">if<\/span> (a <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-keyword\">byte<\/span> b) {\n  System.out.println(<span class=\"hljs-string\">\"b = \"<\/span> + b);\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>Der Code ist wie folgt zu lesen: Wenn der Wert der Variablen <code>a<\/code> auch in einer <code>byte<\/code>-Variablen gespeichert werden kann, dann weise der <code>byte<\/code>-Variablen <code>b<\/code> diesen Wert zu und gebe diesen aus.<\/p>\n\n\n\n<p>F\u00fcr <code>a = 5<\/code> w\u00e4re das z. B. der Fall, f\u00fcr <code>a = 1000<\/code> hingegen nicht, da <code>byte<\/code> lediglich Werte von -128 bis 127 speichern kann.<\/p>\n\n\n\n<p>Genau wie bei Objekten darfst du auch bei primitiven Typen direkt im <code>instanceof<\/code>-Check mit <code>&amp;&amp;<\/code> weitere Pr\u00fcfungen anschlie\u00dfen. Der folgende Code z. B. gibt nur positive <code>byte<\/code>-Werte (also 1 bis 127) aus:<\/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\"><span class=\"hljs-keyword\">int<\/span> a = ...\n<span class=\"hljs-keyword\">if<\/span> (a <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-keyword\">byte<\/span> b &amp;&amp; b &gt; <span class=\"hljs-number\">0<\/span>) {\n  System.out.println(<span class=\"hljs-string\">\"b = \"<\/span> + b);\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>Zahlreiche weitere Beispiele und Besonderheiten findest du im Hauptartikel <a href=\"https:\/\/www.happycoders.eu\/de\/java\/primitive-type-patterns\/\">Primitive Typen in Patterns, instanceof und switch<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Primitive Typ-Pattern mit switch<\/h4>\n\n\n\n<p>Wir k\u00f6nnen primitive Pattern nicht nur in <code>instanceof<\/code> einsetzen, sondern auch in <code>switch<\/code>:<\/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\">double<\/span> value = ...\n<span class=\"hljs-keyword\">switch<\/span> (value) {\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">byte<\/span>   b -&gt; System.out.println(value + <span class=\"hljs-string\">\" instanceof byte:   \"<\/span> + b);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">short<\/span>  s -&gt; System.out.println(value + <span class=\"hljs-string\">\" instanceof short:  \"<\/span> + s);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">char<\/span>   c -&gt; System.out.println(value + <span class=\"hljs-string\">\" instanceof char:   \"<\/span> + c);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">int<\/span>    i -&gt; System.out.println(value + <span class=\"hljs-string\">\" instanceof int:    \"<\/span> + i);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">long<\/span>   l -&gt; System.out.println(value + <span class=\"hljs-string\">\" instanceof long:   \"<\/span> + l);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">float<\/span>  f -&gt; System.out.println(value + <span class=\"hljs-string\">\" instanceof float:  \"<\/span> + f);\n  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-keyword\">double<\/span> d -&gt; System.out.println(value + <span class=\"hljs-string\">\" instanceof double: \"<\/span> + d);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Hier m\u00fcssen wir \u2013 genau wie bei Objekttypen \u2013 das Prinzip der dominierenden und dominierten Typen sowie die Vollst\u00e4ndigkeitspr\u00fcfung beachten. Was das genau bedeutet erf\u00e4hrst du im Hauptartikel <a href=\"https:\/\/www.happycoders.eu\/de\/java\/primitive-type-patterns\/\">Primitive Typen in Patterns, instanceof und switch<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"wiedervorgelegte-preview-und-incubator-features\">Wiedervorgelegte Preview und Incubator-Features<\/h2>\n\n\n\n<p>Sieben Preview- und Incubator-Features werden in Java 23 wiedervorgelegt, drei davon ohne \u00c4nderungen gegen\u00fcber Java 22:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"stream-gatherers-second-preview-jep-473\">Stream Gatherers (Second Preview) \u2013 JEP 473<\/h3>\n\n\n\n<p>Seit der Einf\u00fchrung der Stream API in Java 8 klagte die Java-Community \u00fcber den eingeschr\u00e4nkten Umfang an intermedi\u00e4ren Stream-Operationen. Operationen wie beispielsweise \u201ewindow\u201d oder \u201efold\u201d wurden schmerzlich vermisst und immer wieder angefordert.<\/p>\n\n\n\n<p>Anstatt sich dem Druck der Community zu beugen und diese Funktionen bereitzustellen, hatten die JDK-Entwickler eine bessere Idee: Sie implementierten eine API, mit der sie selbst und auch alle anderen Java Developer selbst intermedi\u00e4re Stream-Operationen implementieren k\u00f6nnen.<\/p>\n\n\n\n<p>Diese neue API nennt sich \u201eStream Gatherers\u201d. Sie wurde erstmals in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-22-features\/#Stream_Gatherers_Preview_-_JEP_461\">Java 22<\/a> durch <a href=\"https:\/\/openjdk.org\/jeps\/461\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 461<\/a> vorgestellt und in Java 23 durch <a href=\"https:\/\/openjdk.org\/jeps\/473\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 473<\/a> unver\u00e4ndert ein zweites Mal als Preview vorgelegt, um weiteres Feedback von der Community einzusammeln.<\/p>\n\n\n\n<p>Mit dem folgenden Code k\u00f6nnten wir z. B. die intermedi\u00e4re Stream-Operation \u201emap\u201d als Stream Gatherer implementieren und einsetzen:<\/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> &lt;T, R&gt; <span class=\"hljs-function\">Gatherer&lt;T, Void, R&gt; <span class=\"hljs-title\">mapping<\/span><span class=\"hljs-params\">(Function&lt;T, R&gt; mapper)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> Gatherer.of(\n      Integrator.ofGreedy(\n          (state, element, downstream) -&gt; {\n            R mappedElement = mapper.apply(element);\n            <span class=\"hljs-keyword\">return<\/span> downstream.push(mappedElement);\n          }));\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> List&lt;Integer&gt; <span class=\"hljs-title\">toLengths<\/span><span class=\"hljs-params\">(List&lt;String&gt; words)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> words.stream()\n      .gather(mapping(String::length))\n      .toList();\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>Wie genau Stream Gatherers funktionieren, welche Einschr\u00e4nkungen es dabei gibt und ob wir endlich die lang ersehnten \u201ewindow\u201d- und \u201efold\u201d-Operationen bekommen, erf\u00e4hrst du im Hauptartikel \u00fcber <a href=\"\/de\/java\/stream-gatherers\/\">Stream Gatherer<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"implicitly-declared-classes-and-instance-main-methods-third-preview-jep-477\">Implicitly Declared Classes and Instance Main Methods (Third Preview) \u2013 JEP 477<\/h3>\n\n\n\n<p>Wenn Java-Entwicklerinnen und -Entwickler ihr erstes Programm schreiben, sieht das \u2013 bisher \u2013 meistens so aus:<\/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\"><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-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>Java-Anf\u00e4nger werden hier mit zahlreichen neuen Konzepten auf einmal konfrontiert:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>mit Klassen,<\/li>\n\n\n\n<li>mit dem Sichtbarkeitsmodifikator <code>public<\/code>,<\/li>\n\n\n\n<li>mit statischen Methoden,<\/li>\n\n\n\n<li>mit unbenutzten Methodenargumenten,<\/li>\n\n\n\n<li>mit <code>System.out<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>W\u00e4re es nicht sch\u00f6n, wenn wir das alles streichen und uns aufs Wesentliche konzentrieren k\u00f6nnten \u2013 so wie in folgendem Screenshot?<\/p>\n\n\n\n<figure class=\"wp-block-image size-full_800\"><img decoding=\"async\" width=\"800\" height=\"152\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-800x152.png\" alt=\"Screenshot for: Implicitly Declared Classes and Instance Main Methods\" class=\"wp-image-40660\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-800x152.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-224x43.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-336x64.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-504x96.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-672x128.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-400x76.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-600x114.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-944x179.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods-1200x228.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/implicitly-declared-classes-instance-main-methods.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<p>Genau das machen \u201eImplicitly Declared Classes and Instance Main Methods\u201c m\u00f6glich!<\/p>\n\n\n\n<p>Ab Java 23 ist der folgende Code ein g\u00fcltiges und vollst\u00e4ndiges Java-Programm:<\/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-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n  println(<span class=\"hljs-string\">\"Hello world!\"<\/span>);\n}<\/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>Wie wird das erm\u00f6glicht?<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Eine Klassenangabe ist nicht mehr zwingend erforderlich. Wird die Klassenangabe weggelassen, erzeugt der Compiler eine implizite Klasse.<\/li>\n\n\n\n<li>Eine <code>main()<\/code>-Methode muss weder <code>public<\/code> noch <code>static<\/code> sein, noch muss sie Argumente haben.<\/li>\n\n\n\n<li>Eine implizite Klasse importiert automatisch die neue Klasse <code>java.io.IO<\/code>, die die statischen Methoden <code>print(...)<\/code>, <code>println(...)<\/code> und <code>readln(...)<\/code> enth\u00e4lt.<\/li>\n<\/ol>\n\n\n\n<p>Weitere Details, Beispiele, zu beachtende Einschr\u00e4nkungen und was bei mehreren \u00fcberladenen <code>main()<\/code>-Methoden passiert, erf\u00e4hrst du im Hauptartikel \u00fcber die <a href=\"\/de\/java\/main-methode\/#compact-source-files-and-instance-main-methods\">Java-main()-Methode<\/a>.<\/p>\n\n\n\n<p>Die hier beschriebenen \u00c4nderungen wurden erstmals in <a href=\"\/de\/java\/java-21-features\/#Unnamed_Classes_and_Instance_Main_Methods_Preview_JEP_445\">Java 21<\/a> unter dem Namen \u201eUnnamed Classes and Instance Main Methods\u201c ver\u00f6ffentlicht. In <a href=\"\/de\/java\/java-22-features\/#Implicitly_Declared_Classes_and_Instance_Main_Methods_Second_Preview_JEP_463\">Java 22<\/a> wurden einige \u00fcberm\u00e4\u00dfig komplizierten Aspekte des Features vereinfacht und das Feature umbenannt.<\/p>\n\n\n\n<p>In Java 23 wurde durch <a href=\"https:\/\/openjdk.org\/jeps\/477\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 477<\/a> die automatisch importierte <code>java.io.IO<\/code>-Klasse hinzugef\u00fcgt, sodass letztendlich auch <code>System.out<\/code> weggelassen werden kann, was im zweiten Preview in Java 22 noch nicht m\u00f6glich war.<\/p>\n\n\n\n<p>In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#simple-source-files-and-instance-main-methods-fourth-preview-jep-495\">Java 24<\/a> wird das Feature erneut umbenannt in \u201eSimple Source Files and Instance Main Methods\u201c.<\/p>\n\n\n\n<p>Bitte bedenke, dass sich das Feature noch im Preview-Stadium befindet und mit der VM-Option <code>--enable-preview<\/code> aktiviert werden muss.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"structured-concurrency-third-preview-jep-480\">Structured Concurrency (Third Preview) \u2013 JEP 480<\/h3>\n\n\n\n<p>Structured Concurrency ist ein moderner, durch <a href=\"\/de\/java\/virtual-threads\/\">virtuelle Threads<\/a> m\u00f6glich gewordener Ansatz, um Aufgaben in parallel auszuf\u00fchrende Teilaufgaben aufzuteilen.<\/p>\n\n\n\n<p>Structured Concurrency bietet eine klare Struktur f\u00fcr den Start und das Ende von parallelen Aufgaben und eine geordnete Fehlerbehandlung. Sollten die Ergebnisse bestimmter Teilaufgaben nicht mehr ben\u00f6tigt werden, k\u00f6nnen diese Teilaufgaben sauber abgebrochen werden.<\/p>\n\n\n\n<p>Ein Beispiel f\u00fcr die Anwendung von Structured Concurrency ist die Implementierung einer <code>race()<\/code>-Methode, die zwei Aufgaben startet und das Ergebnis der zuerst beendeten Aufgabe zur\u00fcckgibt, w\u00e4hrend die andere Aufgabe automatisch abgebrochen wird:<\/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-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> &lt;R&gt; <span class=\"hljs-function\">R <span class=\"hljs-title\">race<\/span><span class=\"hljs-params\">(Callable&lt;R&gt; task1, Callable&lt;R&gt; task2)<\/span>\n    <span class=\"hljs-keyword\">throws<\/span> InterruptedException, ExecutionException <\/span>{\n  <span class=\"hljs-keyword\">try<\/span> (<span class=\"hljs-keyword\">var<\/span> scope = <span class=\"hljs-keyword\">new<\/span> StructuredTaskScope.ShutdownOnSuccess&lt;R&gt;()) {\n    scope.fork(task1);\n    scope.fork(task2);\n    scope.join();\n    <span class=\"hljs-keyword\">return<\/span> scope.result();\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>Eine ausf\u00fchrlichere Beschreibung, weitere Einsatzm\u00f6glichkeiten und zahlreiche Beispiele findest du im Hauptartikel \u00fcber <a href=\"\/de\/java\/structured-concurrency-structuredtaskscope\/\">Structured Concurrency<\/a>.<\/p>\n\n\n\n<p>Structured Concurrency wurde in <a href=\"\/de\/java\/java-21-features\/#Structured_Concurrency_Preview_JEP_453\">Java 21<\/a> als Preview-Feature vorgestellt und in <a href=\"\/de\/java\/java-22-features\/#structured-concurrency-second-preview-jep-462\">Java 22<\/a> ohne \u00c4nderungen erneut vorgelegt. Auch in Java 23, in <a href=\"https:\/\/openjdk.org\/jeps\/480\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 480<\/a>, gab es keine \u00c4nderungen \u2013 die JDK-Entwickler erhoffen sich weiteres Feedback vor der Finalisierung des Features.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"scoped-values-third-preview-jep-481\">Scoped Values (Third Preview) \u2013 JEP 481<\/h3>\n\n\n\n<p>Scoped Values k\u00f6nnen benutzt werden, um Werte an weit entfernte Methodenaufrufe zu \u00fcbergeben, ohne dass diese durch alle Methoden der Aufrufkette als Paramter hindurchgeschleift werden m\u00fcssen.<\/p>\n\n\n\n<p>Das klassische Beispiel ist der auf einem Webserver eingeloggte User, f\u00fcr den ein bestimmter Use Case ausgef\u00fchrt werden soll. Viele der im Rahmen solch eines Use Cases aufgerufenen Methoden ben\u00f6tigen Zugriff auf die User-Informationen. Mit Scoped Values k\u00f6nnen wir einen Kontext aufspannen, innerhalb dessen alle Methoden auf das User-Objekt zugreifen k\u00f6nnen, ohne dass dieses als Parameter an all diese Methoden \u00fcbergeben werden muss.<\/p>\n\n\n\n<p>Aufgespannt wird so ein Kontext mit <code>ScopedValue.where(...)<\/code>:<\/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-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Server<\/span> <\/span>{\n  <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">static<\/span> ScopedValue&lt;User&gt; LOGGED_IN_USER = ScopedValue.newInstance();\n  . . .\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">serve<\/span><span class=\"hljs-params\">(Request request)<\/span> <\/span>{\n    . . .\n    User loggedInUser = authenticateUser(request);\n    ScopedValue.where(LOGGED_IN_USER, loggedInUser)\n               .run(() -&gt; restAdapter.processRequest(request));\n    . . .\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>Nun k\u00f6nnen die innerhalb der <code>run(...)<\/code>-Methode aufgerufene Methode \u2013 sowie alle von ihr direkt oder indirekt aufgerufenen Methoden, z. B. eine tief im Call-Stack aufgerufene Repository-Methode \u2013 wie folgt auf den User zugreifen:<\/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\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Repository<\/span> <\/span>{\n  . . .\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Data <span class=\"hljs-title\">getData<\/span><span class=\"hljs-params\">(UUID id)<\/span> <\/span>{\n    Data data = findById(id);\n    User loggedInUser = Server.LOGGED_IN_USER.get();\n    <span class=\"hljs-keyword\">if<\/span> (loggedInUser.isAdmin()) {\n      enrichDataWithAdminInfos(data);\n    }\n    <span class=\"hljs-keyword\">return<\/span> data;\n  }\n  . . .\n}<\/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>Wer schon einmal mit <em>ThreadLocal<\/em>-Variablen gearbeitet hat, wird eine \u00c4hnlichkeit erkennen. Scoped Values haben jedoch eine ganze Reihe Vorteile gegen\u00fcber <em>ThreadLocals<\/em>. Was diese Vorteile sind, erf\u00e4hrst du neben einer umfassenden Einf\u00fchrung im <a href=\"\/de\/java\/scoped-values\/\">Hauptartikel \u00fcber Scoped Values<\/a>.<\/p>\n\n\n\n<p>Scoped Values wurden gemeinsam mit Structured Concurrency in <a href=\"\/de\/java\/java-21-features\/#Scoped_Values_Preview_JEP_446\">Java 21<\/a> als Preview-Feature eingef\u00fchrt und in <a href=\"\/de\/java\/java-22-features\/#scoped-values-second-preview-jep-464\">Java 22<\/a> ohne \u00c4nderungen in eine zweite Preview-Runde geschickt.<\/p>\n\n\n\n<p>Durch <a href=\"https:\/\/openjdk.org\/jeps\/481\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 481<\/a> wurden in Java 23 die folgenden zwei statischen Methoden der <code>ScopedValue<\/code>-Klasse zu einer Methode zusammengefasst:<\/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\"><span class=\"hljs-comment\">\/\/ Java 22:<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> &lt;T, R&gt; <span class=\"hljs-function\">R <span class=\"hljs-title\">getWhere<\/span> <span class=\"hljs-params\">(ScopedValue&lt;T&gt; key, T value, Supplier&lt;? extends R&gt; op)<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> &lt;T, R&gt; R <span class=\"hljs-title\">callWhere<\/span><span class=\"hljs-params\">(ScopedValue&lt;T&gt; key, T value, Callable&lt;? extends R&gt; op)<\/span> <\/span><\/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>Die Methoden unterschieden sich lediglich dadurch, dass an <code>getWhere(...)<\/code> ein <code>Supplier<\/code> \u00fcbergeben wird (ein funktionales Interface mit einer <code>get()<\/code>-Methode, das <em>keine<\/em> Exception deklariert) und an <code>callWhere(...)<\/code> ein <code>Callable<\/code> (ein funktionales Interface mit einer <code>call()<\/code>-Methode, die <code>throws Exception<\/code> deklariert).<\/p>\n\n\n\n<p>Nehmen wir an, wir wollen im Kontext des Scoped Values folgende Methode aufrufen, wobei <code>SpecificException<\/code> eine checked Exception ist:<\/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-function\">Result <span class=\"hljs-title\">doSomethingSmart<\/span><span class=\"hljs-params\">()<\/span> <span class=\"hljs-keyword\">throws<\/span> SpecificException <\/span>{\n  . . .\n}<\/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>In Java 22 mussten wir diese Methode wie folgt aufrufen:<\/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-comment\">\/\/ Java 22:<\/span>\n<span class=\"hljs-keyword\">try<\/span> {\n  Result result = ScopedValue.callWhere(USER, loggedInUser, <span class=\"hljs-keyword\">this<\/span>::doSomethingSmart);\n} <span class=\"hljs-keyword\">catch<\/span> (Exception e) { <span class=\"hljs-comment\">\/\/ \u27f5 Catching generic Exception<\/span>\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>Da <code>Callable.call()<\/code> eine generische <code>Exception<\/code> wirft, mussten wir eben auch <code>Exception<\/code> abfangen, selbst wenn die aufgerufene Methode eine <em>spezifische<\/em> Exception geworfen hat.<\/p>\n\n\n\n<p>In Java 23 gibt es nun nur noch eine <code>callWhere(...)<\/code>-Methode:<\/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\">public<\/span> <span class=\"hljs-keyword\">static<\/span> &lt;T, R, X extends Throwable&gt; <span class=\"hljs-function\">R <span class=\"hljs-title\">callWhere<\/span><span class=\"hljs-params\">(\n    ScopedValue&lt;T&gt; key, T value, ScopedValue.CallableOp&lt;? extends R, X&gt; op)<\/span> <span class=\"hljs-keyword\">throws<\/span> X<\/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>Statt eines <code>Supplier<\/code>s oder eines <code>Callable<\/code>s wird nun eine <code>ScopedValue.CallableOp<\/code> \u00fcbergeben. Dies ist ein wie folgt definiertes funktionales Interface:<\/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-meta\">@FunctionalInterface<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">ScopedValue<\/span>.<span class=\"hljs-title\">CallableOp<\/span>&lt;<span class=\"hljs-title\">T<\/span>, <span class=\"hljs-title\">X<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Throwable<\/span>&gt; <\/span>{\n    <span class=\"hljs-function\">T <span class=\"hljs-title\">call<\/span><span class=\"hljs-params\">()<\/span> <span class=\"hljs-keyword\">throws<\/span> X\n}<\/span><\/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>Dieses neue Interface enth\u00e4lt eine m\u00f6glicherweise geworfene Exception als Typ-Parameter <code>X<\/code>. Somit kann der Compiler erkennen, welche Art von Exception der Aufruf von <code>callWhere(...)<\/code> werfen kann \u2013 und wir k\u00f6nnen im <code>catch<\/code>-Block direkt <code>SpecificException<\/code> behandeln:<\/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\"><span class=\"hljs-comment\">\/\/ Java 23:<\/span>\n<span class=\"hljs-keyword\">try<\/span> {\n  Result result = ScopedValue.callWhere(USER, loggedInUser, () -&gt; doSomethingSmart());\n} <span class=\"hljs-keyword\">catch<\/span> (SpecificException e) { <span class=\"hljs-comment\">\/\/ \u27f5 Catching SpecificException<\/span>\n  . . .\n}<\/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 wenn <code>doSomethingSmart()<\/code> keine Exception oder eine <code>RuntimeException<\/code> wirft, k\u00f6nnen wir den catch-Block weglassen:<\/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-comment\">\/\/ Java 23:<\/span>\nResult result = callWhere(USER, loggedInUser, <span class=\"hljs-keyword\">this<\/span>::doSomethingSmart);<\/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>Diese \u00c4nderung in Java 23 macht den Code ausdrucksst\u00e4rker und weniger fehleranf\u00e4llig.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"flexible-constructor-bodies-second-preview-jep-482\">Flexible Constructor Bodies (Second Preview) \u2013 JEP 482<\/h3>\n\n\n\n<p>Nehmen wir mal an, du hast eine Klasse, wie die folgende:<\/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\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ConstructorTestParent<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> a;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">ConstructorTestParent<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> a)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">this<\/span>.a = a;\n    printMe();\n  }\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">printMe<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    System.out.println(<span class=\"hljs-string\">\"a = \"<\/span> + a);\n  }\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>Und nehmen wir an, du hast eine zweite Klasse, die diese Klasse erweitert:<\/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\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ConstructorTestChild<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">ConstructorTestParent<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> b;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">ConstructorTestChild<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> a, <span class=\"hljs-keyword\">int<\/span> b)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">super<\/span>(a);\n    <span class=\"hljs-keyword\">this<\/span>.b = b;\n  }\n}<\/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 jetzt w\u00fcrdest du gerne im Konstruktur von <code>ConstructorTestChild<\/code> sicherstellen, dass <code>a<\/code> und <code>b<\/code> nicht negativ sind, bevor der Super-Konstruktor aufgerufen wird.<\/p>\n\n\n\n<p>Eine entsprechende Pr\u00fcfung <em>vor<\/em> den Konstruktor zu setzen, war bisher nicht erlaubt. Deshalb mussten wir uns mit Verrenkungen wie der folgenden aushelfen:<\/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\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ConstructorTestChild<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">ConstructorTestParent<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> b;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">ConstructorTestChild<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> a, <span class=\"hljs-keyword\">int<\/span> b)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">super<\/span>(verifyParamsAndReturnA(a, b));\n    <span class=\"hljs-keyword\">this<\/span>.b = b;\n  }\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">verifyParamsAndReturnA<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> a, <span class=\"hljs-keyword\">int<\/span> b)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">if<\/span> (a &lt; <span class=\"hljs-number\">0<\/span> || b &lt; <span class=\"hljs-number\">0<\/span>) <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> IllegalArgumentException();\n    <span class=\"hljs-keyword\">return<\/span> a;\n  }\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>Das ist weder sehr elegant noch gut lesbar.<\/p>\n\n\n\n<p>Nehmen wir weiterhin an, du m\u00f6chtest die im Konstruktor der Elternklasse aufgerufene <code>printMe()<\/code> Methode \u00fcberschreiben, um zus\u00e4tzlich die Felder der abgeleiteten Klasse auszugeben:<\/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\">ConstructorTestChild<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">ConstructorTestParent<\/span> <\/span>{\n  . . .\n  <span class=\"hljs-meta\">@Override<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">printMe<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">super<\/span>.printMe();\n    System.out.println(<span class=\"hljs-string\">\"b = \"<\/span> + b);\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>Was w\u00fcrde diese Methode ausgeben, wenn du <code>new ConstructorTestChild(1, 2)<\/code> aufrufst?<\/p>\n\n\n\n<p>Sie w\u00fcrde nicht etwa <code>a = 1<\/code> und <code>b = 2<\/code> ausgeben, sondern:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">a = 1\nb = 0<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><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>b<\/code> ist zu diesem Zeitpunkt noch gar nicht initialisiert. Es wird ja erst <em>nach<\/em> dem Aufruf von <code>super(...)<\/code>, also des Konstruktors, der wiederrum <code>printMe()<\/code> aufruft, initialisiert.<\/p>\n\n\n\n<p>Beide Probleme geh\u00f6ren mit \u201eFlexible Constructor Bodies\u201d der Vergangenheit an.<\/p>\n\n\n\n<p>Zum einen darf in Zukunft vor dem Aufruf des Super-Konstruktors mit <code>super(...)<\/code> \u2013 und auch vor dem Aufruf eines alternativen Konstruktors mit <code>this(...)<\/code> \u2013 jeglicher Code ausgef\u00fchrt werden, der nicht auf die gerade konstruierte Instanz, also auch nicht auf deren Felder zugreift (dies wurde bereits in <a href=\"\/de\/java\/java-22-features\/#statements-before-super-preview-jep-447\">Java 22<\/a> durch <a href=\"https:\/\/openjdk.org\/jeps\/447\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 447<\/a> erm\u00f6glicht).<\/p>\n\n\n\n<p>Zum anderen d\u00fcrfen die Felder der gerade konstruierten Instanz jedoch <em>initialisiert<\/em> werden. Dies wurde in Java 23 durch <a href=\"https:\/\/openjdk.org\/jeps\/482\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 482<\/a> m\u00f6glich. <\/p>\n\n\n\n<p>Das erlaubt es nun, den Code wie folgt umzuschreiben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-39\" 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\">ConstructorTestChild<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">ConstructorTestParent<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> b;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">ConstructorTestChild<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> a, <span class=\"hljs-keyword\">int<\/span> b)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">if<\/span> (a &lt; <span class=\"hljs-number\">0<\/span> || b &lt; <span class=\"hljs-number\">0<\/span>) <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> IllegalArgumentException();  <span class=\"hljs-comment\">\/\/ \u27f5 Now allowed!<\/span>\n    <span class=\"hljs-keyword\">this<\/span>.b = b;                                                <span class=\"hljs-comment\">\/\/ \u27f5 Now allowed!<\/span>\n    <span class=\"hljs-keyword\">super<\/span>(a);\n  }\n\n  <span class=\"hljs-meta\">@Override<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">printMe<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">super<\/span>.printMe();\n    System.out.println(<span class=\"hljs-string\">\"b = \"<\/span> + b);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><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 Aufruf von <code>new ConstructorTestChild(1, 2)<\/code> f\u00fchrt nun zur erwarteten Ausgabe:<\/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\">a = 1\nb = 2<\/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>Der neue Code ist zum einen einfacher zu lesen und zum anderen sicherer, da so die Gefahr einged\u00e4mmt werden kann, dass in \u00fcberschriebenen Methoden in abgeleiteten Klassen auf ein uninitialisiertes Feld zugegriffen wird.<\/p>\n\n\n\n<p>Weitere Beispiele und einige zu beachtende Besonderheiten findest du im Hauptartikel \u00fcber <a href=\"\/de\/java\/flexible-constructor-bodies\/\">Flexible Constructor Bodies<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"class-file-api-second-preview-jep-466\">Class-File API (Second Preview) \u2013 JEP 466<\/h3>\n\n\n\n<p>Das Java Class-File API ist eine Schnittstelle zum Lesen und Schreiben von <em>.class<\/em>-Dateien, also von kompiliertem Java-Bytecode. Sie soll das im JDK weit verbreitete Bytecode-Manipulations-Framework <a href=\"https:\/\/asm.ow2.io\/\" target=\"_blank\" rel=\"noopener\">ASM<\/a> ersetzen.<\/p>\n\n\n\n<p>Das Class-File-API wurde in <a href=\"\/de\/java\/java-22-features\/#Class-File_API_Preview_JEP_457\">Java 22<\/a> als Preview-Feature vorgestellt und in Java 23 durch <a href=\"https:\/\/openjdk.org\/jeps\/466\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 466<\/a> mit einigen Verbesserungen in eine zweite Preview-Runde geschickt.<\/p>\n\n\n\n<p>Da vermutlich nur wenige Java-Entwicklerinnen und -Entwickler direkt mit der Class-File-API arbeiten werden, sondern in aller Regel indirekt durch andere Tools, werde ich die neue Schnittstelle hier, wie auch schon im Java-22-Artikel, nicht im Detail beschreiben.<\/p>\n\n\n\n<p>Falls das Class-File-API f\u00fcr dich von Interesse ist, findest du alle Details in <a href=\"https:\/\/openjdk.org\/jeps\/466\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 466<\/a>. Oder schreib einen Kommentar unter den Artikel! Sollte wider Erwarten ein hinreichendes Interesse bestehen, werde ich gerne einen Artikel \u00fcber die Class-File-API schreiben.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vector-api-eighth-incubator-jep-469\">Vector API (Eighth Incubator) \u2013 JEP 469<\/h3>\n\n\n\n<p>Dreieinhalb Jahre ist es nun her, dass die Vector API erstmals als Incubator-Feature im JDK enthalten war. Und auch in Java 23 wird sie ohne \u00c4nderungen im Incubator-Stadium verbleiben, spezifiziert durch <a href=\"https:\/\/openjdk.org\/jeps\/469\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 469<\/a>. <\/p>\n\n\n\n<p>Die Vector-API wird es erm\u00f6glichen, Vektorberechnungen wie die folgende auf spezielle Operationen moderner CPUs abzubilden. Dadurch werden solche Berechnungen extrem schnell durchgef\u00fchrt werden k\u00f6nnen \u2013 bis zu einer bestimmten Vektorgr\u00f6\u00dfe in nur einem einzigen CPU-Zyklus!<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-half_400\"><img decoding=\"async\" width=\"400\" height=\"91\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-400x91.png\" alt=\"java vector addition\" class=\"wp-image-25531\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-400x91.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-224x51.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-336x76.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-504x115.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-672x153.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-600x137.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition.png 800w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><figcaption class=\"wp-element-caption\">Beispiel einer Vektoraddition<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Ich werde die Vector-API im Detail beschreiben, sobald sie das Preview-Stadium erreicht hat. Das wird vorraussichtlich dann der Fall sein, wenn auch die f\u00fcr die Vector-API notwendigen Funktionen von <a href=\"https:\/\/openjdk.org\/projects\/valhalla\/\">Project Valhalla<\/a> im Preview-Stadium verf\u00fcgbar sind (was laut Aussage der Valhalla-Entwickler seit etwa einem Jahr \u201ebald\u201d der Fall sein soll).<\/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 diesem Abschnitt findest du einen \u00dcberblick \u00fcber Features, die als <em>deprecated<\/em> markiert oder komplett aus dem JDK entfernt wurden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecate-the-memory-access-methods-in-sun-misc-unsafe-for-removal-jep-471\">Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal \u2013 JEP 471<\/h3>\n\n\n\n<p>Die <code>sun.misc.Unsafe<\/code>-Klasse wurde 2002 mit Java 1.4 eingef\u00fchrt. Ein Gro\u00dfteil ihrer Methoden dient dem direkten Zugriff auf Speicher \u2013 sowohl auf den Java-Heap als auch auf nicht vom Heap kontrollierten, also nativen Speicher.<\/p>\n\n\n\n<p>Wie der Name der Klasse schon andeutet, sind die meisten dieser Operationen unsicher, d. h. sie k\u00f6nnen zu undefiniertem Verhalten, Leistungseinbu\u00dfen oder Systemabst\u00fcrzen f\u00fchren, wenn sie nicht korrekt eingesetzt werden. <\/p>\n\n\n\n<p><code>Unsafe<\/code> war urspr\u00fcnglich nur f\u00fcr JDK-interne Zwecke gedacht \u2013 doch in Java 1.4 gab es zum einen noch kein Modulsystem, dass diese Klasse vor uns Entwicklern h\u00e4tte verstecken k\u00f6nnen \u2013 und zum anderen gab es keine Alternativen, wollte man bestimmte Operationen m\u00f6glichst performant implementieren (z. B. Compare-and-Swap) oder auf gr\u00f6\u00dfere Off-Heap-Speicherbl\u00f6cke als 2 GB zugreifen (das ist das Limit von <a href=\"\/de\/java\/bytebuffer-flip-compact\/\">ByteBuffer<\/a>).<\/p>\n\n\n\n<p>Heute jedoch existieren Alternativen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In Java 9 wurden <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/22\/docs\/api\/java.base\/java\/lang\/invoke\/VarHandle.html\" target=\"_blank\" rel=\"noopener\">VarHandles<\/a> eingef\u00fchrt, die direkten und optimierten Zugriff auf On-Heap-Speicher erm\u00f6glichen, dabei verschiedene Arten von Memory Barriers setzen k\u00f6nnen und auch atomare Operationen wie Compare-and-Swap bereitstellen.<\/li>\n\n\n\n<li>In <a href=\"\/de\/java\/java-22-features\/\">Java 22<\/a> wurde die <a href=\"\/de\/java\/foreign-function-memory-api\/\">Foreign Function &amp; Memory API<\/a> finalisiert, eine Schnittstelle zum Aufruf von Funktionen in nativen Libraries und zur Verwaltung von nativem, also Off-Heap-Speicher.<\/li>\n<\/ul>\n\n\n\n<p>Aufgrund der Verf\u00fcgbarkeit dieser stabilen, sicheren und performanten Alternativen entschieden die JDK-Entwickler in <a href=\"https:\/\/openjdk.org\/jeps\/471\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 471<\/a>, alle <code>Unsafe<\/code>-Methoden f\u00fcr den Zugriff auf On-Heap- und Off-Heap-Speicher in Java 23 als <em>deprecated for removal<\/em> zu kennzeichnen und in einer zuk\u00fcnftigen Java-Version zu entfernen.<\/p>\n\n\n\n<p>Die Entfernung wird in vier Phasen durchgef\u00fchrt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Phase 1: In Java 23 werden die Methoden als <em>deprecated for removal<\/em> markiert, so dass es bei deren Verwendung zu Kompilerwarnungen kommt.<\/li>\n\n\n\n<li>Phase 2: Vorraussichtlich in Java 25 wird die Verwendung dieser Methoden auch zu Laufzeitwarnungen f\u00fchren.<\/li>\n\n\n\n<li>Phase 3: Vorraussichtlich in Java 26 werden die Methoden <code>UnsupportedOperationException<\/code>s werfen.<\/li>\n\n\n\n<li>Phase 4: Die Methoden werden entfernt. In welchem Release dies geschehen wird, ist noch nicht festgelegt.<\/li>\n<\/ul>\n\n\n\n<p>Das Default-Verhalten in den jeweiligen Phasen kann durch die VM-Option <code>--sun-misc-unsafe-memory-access<\/code> \u00fcberschrieben werden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>--sun-misc-unsafe-memory-access=allow<\/code> \u2013 alle Unsafe-Methoden d\u00fcrfen verwendet werden. Es werden zwar Kompilerwarnungen angezeigt, aber keine Warnungen zur Laufzeit ausgegeben (Standardeinstellung in Phase 1).<\/li>\n\n\n\n<li><code>--sun-misc-unsafe-memory-access=warn<\/code> \u2013 zur Laufzeit wird eine Warnung angezeit, sobald eine der betroffenen Methoden das erste Mal aufgerufen wird (Standardeinstellung in Phase 2).<\/li>\n\n\n\n<li><code>--sun-misc-unsafe-memory-access=debug<\/code> \u2013 zur Laufzeit wird eine Warnung und ein Stacktrace ausgegeben, wann immer eine der betroffenen Methoden aufgerufen wird.<\/li>\n\n\n\n<li><code>--sun-misc-unsafe-memory-access=deny<\/code> \u2013 die betroffenen Methoden werfen eine <code>UnsupportedOperationException<\/code> (Standardeinstellung in Phase 3).<\/li>\n<\/ul>\n\n\n\n<p>In den Phasen 2 und 3 kann dabei jeweils nur das Verhalten der jeweils vorherigen Phase aktiviert werden, und in Phase 4 wird diese VM-Option keinen Effekt mehr haben.<\/p>\n\n\n\n<p>Eine vollst\u00e4ndige Liste aller als <em>deprecated<\/em> markierten Methoden mit ihrem jeweiligen Ersatz findest du im Abschnitt <a href=\"https:\/\/openjdk.org\/jeps\/471#sun-misc-Unsafe-memory-access-methods-and-their-replacements\" target=\"_blank\" rel=\"noopener\">sun.misc.Unsafe memory-access methods and their replacements<\/a> des JEPs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"thread-suspend-resume-and-threadgroup-suspend-resume-are-removed\">Thread.suspend\/resume and ThreadGroup.suspend\/resume are removed<\/h3>\n\n\n\n<p>Bereits in Java 1.2 wurden die f\u00fcr Deadlocks anf\u00e4lligen Methoden <code>Thread.suspend()<\/code>, <code>Thread.resume<\/code>(), <code>ThreadGroup.suspend()<\/code> und <code>ThreadGroup.resume()<\/code> als <em>deprecated<\/em> markiert.<\/p>\n\n\n\n<p>In <a href=\"\/de\/java\/java-14-features\/#Thread_SuspendResume_Are_Deprecated_for_Removal\">Java 14<\/a> wurden diese Methoden dann als <em>deprecated for removal<\/em> deklariert.<\/p>\n\n\n\n<p>Seit <a href=\"\/de\/java\/java-19-features\/#javalangThreadGroup_is_degraded\">Java 19<\/a> werfen <code>ThreadGroup.suspend()<\/code> und <code>resume()<\/code> eine <code>UnsupportedOperationException<\/code> \u2013 und seit <a href=\"\/de\/java\/java-20-features\/#Threadsuspendresume_changed_to_throw_UnsupportedOperationException\">Java 20<\/a> auch <code>Thread.suspend()<\/code> und <code>resume()<\/code>.<\/p>\n\n\n\n<p>In Java 23 wurden all diese Methoden schlie\u00dflich entfernt.<\/p>\n\n\n\n<p>F\u00fcr diese \u00c4nderung gibt es keinen JEP, sie ist im Bug-Tracker unter <a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8320532\" target=\"_blank\" rel=\"noopener\">JDK-8320532<\/a> registriert.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"threadgroup-stop-is-removed\">ThreadGroup.stop is removed<\/h3>\n\n\n\n<p>Ebenfalls in Java 1.2 wurde <code>ThreadGroup.stop()<\/code> als <em>deprecated<\/em> markiert, da das Konzept zum Stoppen einer Thread-Gruppe von Anfang an mangelhaft implementiert war.<\/p>\n\n\n\n<p>In <a href=\"\/de\/java\/java-16-features\/#Terminally_Deprecated_ThreadGroup_stop_destroy_isDestroyed_setDaemon_and_isDaemon\">Java 16<\/a> wurde die Methode als <em>deprecated for removal<\/em> deklariert.<\/p>\n\n\n\n<p>Seit <a href=\"\/de\/java\/java-19-features\/#javalangThreadGroup_is_degraded\">Java 19<\/a> wirft <code>ThreadGroup.stop()<\/code> eine <code>UnsupportedOperationException<\/code>.<\/p>\n\n\n\n<p>In Java 23 wurde diese Methode schlie\u00dflich entfernt.<\/p>\n\n\n\n<p>F\u00fcr diese \u00c4nderung gibt es keinen JEP, sie ist im Bug-Tracker unter <a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8320786\" target=\"_blank\" rel=\"noopener\">JDK-8320786<\/a> registriert.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-23\">Sonstige \u00c4nderungen in Java 23<\/h2>\n\n\n\n<p>In diesem Abschnitt findest du \u00c4nderungen, mit denen die meisten Java-Entwicklerinnen und -Entwickler nicht in ihrer t\u00e4glichen Arbeit konfrontiert sind. Nat\u00fcrlich ist es dennoch gut, \u00fcber diese \u00c4nderungen Bescheid zu wissen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zgc-generational-mode-by-default-jep-474\">ZGC: Generational Mode by Default \u2013 JEP 474<\/h3>\n\n\n\n<p>In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-21-features\/#Generational_ZGC_-_JEP_439\">Java 21<\/a> wurde der \u201eGenerational Mode\u201d des Z Garbage Collectors (ZGC) eingef\u00fchrt. In diesem Modus macht sich der ZGC die \u201eschwache Generationshypothese\u201d (englisch: \u201eWeak Generational Hypothesis\u201d) zu Nutze und legt neue und alte Objekte in zwei separaten Bereichen ab: der \u201ejungen Generation\u201d und der \u201ealten Generation\u201d. Die junge Generation enth\u00e4lt haupts\u00e4chlich kurzlebige Objekte und wird h\u00e4ufiger bereinigt, w\u00e4hrend die alte Generation langlebige Objekte enth\u00e4lt und seltener aufger\u00e4umt werden muss.<\/p>\n\n\n\n<p>In Java 21 musste der Generational Mode mit der VM Option <code>-XX:+UseZGC -XX:+ZGenerational<\/code> aktiviert werden.<\/p>\n\n\n\n<p>Da der Generational Mode f\u00fcr die meisten Anwendungsf\u00e4lle zu beachtlichen Leistungssteigerungen f\u00fchrt, wird der Modus in Java 23 durch <a href=\"https:\/\/openjdk.org\/jeps\/474\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 474<\/a> standardm\u00e4\u00dfig aktiviert.<\/p>\n\n\n\n<p>D. h. durch die VM-Option <code>-XX:+UseZGC<\/code> wird ZGC automatisch im Generational Mode aktiviert.<\/p>\n\n\n\n<p>Deaktivieren kannst du den Generational Mode durch <code>-XX:+UseZGC -XX:-ZGenerational<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"annotation-processing-in-javac-disabled-by-default\">Annotation processing in javac disabled by default<\/h3>\n\n\n\n<p>Falls du ein Projekt mit <a href=\"https:\/\/projectlombok.org\/\" target=\"_blank\" rel=\"noopener\">Lombok-Annotationen<\/a> auf Java 23 aktualisiert hast, k\u00f6nnte es sein, dass das Projekt nicht mehr ohne weiteres compiliert.<\/p>\n\n\n\n<p>Das liegt daran, dass in Java 23 das Annotation Processing standardm\u00e4\u00dfig deaktiviert wurde. Der Grund daf\u00fcr ist, dass durch Annotation Processing potentiell schadhafter Code ausgef\u00fchrt werden k\u00f6nnte.<\/p>\n\n\n\n<p>Um Annotation Processing wieder zu aktivieren, hast du folgende zwei Optionen:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Empfohlen: \u00dcber die <code>javac<\/code>-Optionen <code>-processor<\/code>, <code>--processor-path<\/code> oder <code>--processor-module-path<\/code> den oder die zu aktivierenden Prozessoren angeben, z. B.:<br><code>javac -processorpath \u2026\/m2repo\/org\/projectlombok\/lombok\/1.18.38\/lombok-1.18.38.jar \u2026<\/code><\/li>\n\n\n\n<li>Aus Sicherheitsgr\u00fcnden nicht empfohlen: \u00fcber die javac-Option <code>-proc:full<\/code> kannst du Annotation Processing f\u00fcr <em>alle<\/em> Prozessoren aktivieren:<br><code>javac -proc:full ...<\/code><\/li>\n<\/ol>\n\n\n\n<p>In einem Maven-Projekt aktivierst du das Annotation Processing f\u00fcr Lombok durch folgenden Eintrag in der <em>pom.xml <\/em>(erfordert <em>maven-compiler-plugin<\/em> 3.8.0 oder h\u00f6her):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-41\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">plugin<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.apache.maven.plugins<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>maven-compiler-plugin<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">configuration<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">annotationProcessorPaths<\/span>&gt;<\/span>\n         <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">path<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.projectlombok<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>lombok<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n         <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">path<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">annotationProcessorPaths<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">configuration<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">plugin<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-41\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In Gradle ist es deutlich einfacher \u2013 hier musst du blo\u00df im <code>dependencies<\/code>-Block folgende Zeile einf\u00fcgen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-42\" data-shcb-language-name=\"Gradle\" data-shcb-language-slug=\"gradle\"><span><code class=\"hljs language-gradle\">annotationProcessor <span class=\"hljs-string\">'org.projectlombok:lombok:1.18.8'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-42\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Gradle<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">gradle<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\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-8321314\" target=\"_blank\" rel=\"noopener\">JDK-8321314<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"removal-of-module-jdk-random\">Removal of Module jdk.random<\/h3>\n\n\n\n<p>Diese \u00c4nderung ist nicht unter \u201eL\u00f6schungen\u201d einsortiert, da nicht wirklich etwas gel\u00f6scht wurde. Alle Klassen des Moduls <code>jdk.random<\/code> wurden in das <code>java.base<\/code>-Modul verschoben.<\/p>\n\n\n\n<p>Solltest du das Java Modulsystem verwenden und irgendwo <code>requires jdk.random<\/code> angegeben haben, dann kannst du diesen Eintrag in Java 23 entfernen (das <code>java.base<\/code>-Modul wird automatisch eingebunden).<\/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-8330005\" target=\"_blank\" rel=\"noopener\">JDK-8330005<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"console-methods-with-explicit-locale\">Console Methods With Explicit Locale<\/h3>\n\n\n\n<p>Mit der in Java 6 eingef\u00fchrten <code>Console<\/code>-Klasse k\u00f6nnen wir bequem Text auf der Konsole ausgeben und User-Eingaben von der Konsole einlesen:<\/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\">Console console = System.console();\n\n<span class=\"hljs-keyword\">var<\/span> name = console.readLine(<span class=\"hljs-string\">\"What's your name (by the way, \u03c0 = %.4f)? \"<\/span>, Math.PI);\n<span class=\"hljs-keyword\">var<\/span> password = console.readPassword(<span class=\"hljs-string\">\"Your password (by the way, e = %.4f)? \"<\/span>, Math.E);\n\nconsole.printf(<span class=\"hljs-string\">\"Your name is %s%n\"<\/span>, name); <span class=\"hljs-comment\">\/\/ `printf` and `format` do the same<\/span>\nconsole.format(<span class=\"hljs-string\">\"Your password starts with %c%n\"<\/span>, password&#091;<span class=\"hljs-number\">0<\/span>]);<\/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>Hierbei wurde immer das Default-Locale verwendet, d. h. je nach Spracheinstellung wurde Pi entweder als 3,1415 (mit Komma) oder 3.1415 (mit Punkt) ausgegeben.<\/p>\n\n\n\n<p>Ab Java 23 kannst du bei den Methoden <code>printf(...)<\/code>, <code>format(...)<\/code>, <code>readLine(...)<\/code> und <code>readPassword(...)<\/code> als zus\u00e4tzlichen Parameter an erster Stelle ein Locale angeben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-44\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Console console = System.console();\n\n<span class=\"hljs-keyword\">var<\/span> name = console.readLine(Locale.US, <span class=\"hljs-string\">\"What's your name (\u03c0 = %.4f)? \"<\/span>, Math.PI);\n<span class=\"hljs-keyword\">var<\/span> password = console.readPassword(Locale.US, <span class=\"hljs-string\">\"Your password (e = %.4f)? \"<\/span>, Math.E);\n \nconsole.printf(Locale.US, <span class=\"hljs-string\">\"Your name is %s%n\"<\/span>, name);\nconsole.format(Locale.US, <span class=\"hljs-string\">\"Your password starts with %c%n\"<\/span>, password&#091;<span class=\"hljs-number\">0<\/span>]);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-44\"><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 Beispiel wird nun Pi immer im amerikanischen Stil, also als 3.1415 ausgegeben.<\/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-8330276\" target=\"_blank\" rel=\"noopener\">JDK-8330276<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"support-for-duration-until-another-instant\">Support for Duration Until Another Instant<\/h3>\n\n\n\n<p>Um die Dauer zwischen zwei <code>Instant<\/code>-Objekten zu bestimmen, musste man bisher <code>Duration.between(...)<\/code> verwenden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-45\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Instant now = Instant.now();\nInstant later = Instant.now().plus(ThreadLocalRandom.current().nextInt(), SECONDS);\nDuration duration = Duration.between(now, later);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-45\"><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 diese Methode nicht leicht auffindbar ist, wurde eine neue Instanz-Methode <code>Instant.until(...)<\/code> eingef\u00fchrt, die exakt die gleiche Berechnung durchf\u00fchrt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-46\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Instant now = Instant.now();\nInstant later = Instant.now().plus(ThreadLocalRandom.current().nextInt(), SECONDS);\nDuration duration = now.until(later);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-46\"><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>(F\u00fcr diese \u00c4nderung gibt es keinen JEP, sie ist im Bug-Tracker unter <a href=\"https:\/\/bugs.openjdk.org\/browse\/JDK-8331202\" target=\"_blank\" rel=\"noopener\">JDK-8331202<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-21\">Relax alignment of array elements<\/h3>\n\n\n\n<p>Auf einem 64-Bit-System arbeitet die JVM bei maximal 32 GB Heap standardm\u00e4\u00dfig mit komprimierten Pointern, den sogenannten \u201e<a href=\"https:\/\/www.happycoders.eu\/de\/java\/compressed-oops\/\">Compressed Oops<\/a>\u201c (OOP = ordinary object pointer) und den \u201e<a href=\"https:\/\/www.happycoders.eu\/de\/java\/object-headers-compressed-class-pointers\/#compressed-class-pointers\">Compressed Class Pointers<\/a>\u201c. Diese komprimierten Pointer sind statt 64 Bit nur 32 Bit lang. Damit werden f\u00fcr jedes Objekt im Arbeitsspeicher 64 Bit (= 8 Byte) eingespart: 32 Bit f\u00fcr den Pointer auf das Objekt und weitere 32 Bit f\u00fcr den Pointer von diesem Objekt auf dessen Klasse.<\/p>\n\n\n\n<p>Mit 32 Bit k\u00f6nnen eigentlich nur 2<sup>32<\/sup> Bytes = 4 GB adressiert werden. Doch die JVM wendet einen Trick an: Sie schiebt diese 32 Bit um drei Stellen nach links, so dass daraus 35 Bit werden (deren letzten drei Bit immer 0 sind). Mit diesen 35 Bit lassen sich dann 2<sup>35<\/sup> = 32 GB adressieren.<\/p>\n\n\n\n<p>Da, wie eben erw\u00e4hnt, die letzten drei Bit immer 0 sind, kann so ein Pointer nicht auf jede beliebige Adresse im Speicher zeigen, sondern nur auf Adressen, die durch 2<sup>3<\/sup> = 8 teilbar sind. Und somit startet jedes Java-Objekt immer an einer durch 8 teilbaren Speicheradresse.<\/p>\n\n\n\n<p>Das galt, aus unerfindlichen Gr\u00fcnden, bisher auch f\u00fcr die Start-Adresse der Array-Daten innerhalb eines Array-Objekts. Standardm\u00e4\u00dfig sind sowohl Compressed Oops als auch Compressed Class Pointers aktiviert, so dass z. B. ein Array mit z. B. drei Bytes (im Beispiel: 0, 8, 15) wie folgt aufgebaut ist:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"190\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-800x190.png\" alt=\"Java array alignment with compressed oops and compressed class pointers\" class=\"wp-image-41205\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-800x190.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-224x53.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-336x80.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-504x120.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-672x160.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-400x95.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-600x143.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-944x224.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a-1200x285.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-a.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n<\/div>\n\n\n<p>Wir sehen hier zun\u00e4chst einen 12-Byte-Header, der aus einem 8-Byte gro\u00dfen \u201eMark word\u201c besteht (das enth\u00e4lt u. a. Informationen f\u00fcr den Garbage Collector und f\u00fcr die Synchronisation) sowie einem 4-Byte gro\u00dfen komprimierten Class Pointer. Darauf folgen ein 4-Byte-Gr\u00f6\u00dfenfeld und die eigentlichen Daten des Arrays. Am Ende liegen f\u00fcnf unbelegte Bytes (\u201ePadding\u201c), da die Gesamtgr\u00f6\u00dfe aus dem o. g. Grund auf einen durch acht teilbaren Wert aufgerundet wird.<\/p>\n\n\n\n<p>So weit, so gut.<\/p>\n\n\n\n<p>Wenn wir allerdings Compressed Class Pointers deaktivieren, dann ergab sich bisher folgendes Bild:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"190\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-800x190.png\" alt=\"Java array alignment with uncompressed class pointers before Java 23\" class=\"wp-image-41206\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-800x190.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-224x53.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-336x80.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-504x120.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-672x160.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-400x95.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-600x143.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-944x224.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b-1200x285.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-b.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n<\/div>\n\n\n<p>Da auch die Start-Adresse der Array-Daten (des blauen Bereichs in der Grafik) bisher durch acht teilbar sein musste, haben wir sowohl einen Verlust von vier Bytes vor den Array-Daten als auch einen weiteren Verlust von f\u00fcnf Bytes am Ende des Objekts, insgesamt also neun Bytes.<\/p>\n\n\n\n<p>Da es keinen Grund daf\u00fcr, gibt auch die Array-Daten an einer durch acht teilbaren Adresse starten zu lassen (es gibt keine komprimierten Pointer dorthin), wurde das Layout bei unkomprimierten Class Pointers in Java 23 wie folgt ge\u00e4ndert:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"190\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-800x190.png\" alt=\"Java array alignment with uncompressed class pointers as of Java 23\" class=\"wp-image-41207\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-800x190.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-224x53.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-336x80.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-504x120.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-672x160.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-400x95.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-600x143.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-944x224.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c-1200x285.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/06\/java-array-alignment-java-23-c.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n<\/div>\n\n\n<p>Der blaue Bereich beginnt nun direkt nach dem Gr\u00f6\u00dfenfeld. Das gleiche Array belegt nun acht Bytes weniger, und es geht nur noch <em>ein<\/em> Byte verloren, nicht mehr neun. Bei einer Anwendung mit vielen kleinen Arrays, kann das in Summe zu einer sp\u00fcrbaren Reduzierung des Speicherbedarfs f\u00fchren.<\/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-8139457\" target=\"_blank\" rel=\"noopener\">JDK-8139457<\/a> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"change-lockingmode-default-from-lm_legacy-to-lm_lightweight\">Change LockingMode default from LM_LEGACY to LM_LIGHTWEIGHT<\/h3>\n\n\n\n<p>In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-21-features\/#Implement_Alternative_Fast-Locking_Scheme\">Java 21<\/a> wurde ein neuer, <a href=\"https:\/\/www.happycoders.eu\/de\/java\/object-headers-compressed-class-pointers\/#lightweight-locking\">leichtgewichtiger Locking-Mechanismus<\/a> eingef\u00fchrt, der mittelfristig das bisherige <a href=\"https:\/\/www.happycoders.eu\/de\/java\/object-headers-compressed-class-pointers\/#legacy-stack-locking\">Stack Locking<\/a> abl\u00f6sen soll.<\/p>\n\n\n\n<p>In&nbsp;<a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-22-features\/#Make_LockingMode_a_product_flag\">Java 22<\/a>&nbsp;wurde diese zun\u00e4chst experimentelle Option zu einer produktiven Option bef\u00f6rdert.<\/p>\n\n\n\n<p>In Java 23 wird <em>Lightweight Locking<\/em> zum Standard-Locking-Mechanismus.<\/p>\n\n\n\n<p>Du kannst vor\u00fcbergehend den bisherigen Default-Modus, <em>Stack Locking<\/em>, durch die VM-Option <code style=\"white-space:nowrap\">-XX:LockingMode=1<\/code> wieder aktivieren.<\/p>\n\n\n\n<p><em>Stack Locking<\/em> wird 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> als \u201edeprecated\u201c markiert und voraussichtlich in Java 27 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-8319251\" target=\"_blank\" rel=\"noopener\">JDK-8319251<\/a><em> registriert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-21\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 23<\/h3>\n\n\n\n<p>In diesem Artikel hast du alle Java-23-Features kennengelernt, die aus JDK Enhancement Proposals (JEPs) hervorgegangen sind, sowie einige weitere ausgew\u00e4hlte \u00c4nderungen aus den Release Notes. Eine vollst\u00e4ndige Liste aller \u00c4nderungen findest du in den <a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/23-relnote-issues.html\" target=\"_blank\" rel=\"noreferrer noopener\">Java 23 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>Java 23 bringt uns drei neue Features und eine Menge an aktualisierten Preview-Features.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Das Schreiben und Lesen von JavaDoc-Kommentaren wird in Zukunft einfacher, da wir ab sofort auch Markdown verwenden d\u00fcrfen.<\/li>\n\n\n\n<li>Statt wie bisher Klassen und Pakete, k\u00f6nnen wir in Zukunft mit <code>import module<\/code> ganze Module importieren und damit den <code>import<\/code>-Block einer <em>.java<\/em>-Datei deutlich \u00fcbersichtlicher machen.<\/li>\n\n\n\n<li><em>Primitive Type Patterns<\/em> erweitern die Pattern-Matching-F\u00e4higkeiten von Java um primitive Typen. Ich kann mir allerdings nicht vorstellen, dass wir diese Art von Pattern Matching oft in unserem Code einsetzen werden (ganz im Gegensatz zu den Pattern-Matching-F\u00e4higkeiten, die Java in den vorherigen Releases hinzubekommen hat).<\/li>\n\n\n\n<li>In implizit deklarierten Klassen d\u00fcrfen wir nun statt <code>System.out.println(...)<\/code> einfach nur <code>println(...)<\/code> schreiben.<\/li>\n\n\n\n<li><code>ScopedValue.callWhere(...)<\/code> bekommt nun eine typisierte <code>CallableOp<\/code> \u00fcbergeben, so dass der Compiler automatisch erkennen kann, ob die aufgerufene Operation eine checked Exception werfen kann \u2013 und wenn ja, welche. So m\u00fcssen wir nicht mehr die generische <code>Exception<\/code> behandeln, sondern die tats\u00e4chlich geworfene. Und die separate <code>ScopedValue.getWhere(<code>...<\/code>)<\/code>-Methode kann dadurch wegfallen.<\/li>\n\n\n\n<li>In Konstruktoren abgeleiter Klassen d\u00fcrfen wir nun vor dem Aufruf von <code>super(...)<\/code> Felder der abgeleiteten Klasse initialisieren. Das ist hilfreich, wenn der Konstruktor der Elternklasse Methoden aufruft, die in der abgeleiteten Klasse \u00fcberschrieben sind und dort auf eben diese Felder zugreifen.<\/li>\n\n\n\n<li>Wer den Z Garbage Collector nutzt, kommt durch das Upgrade auf Java 23 automatisch in den Genuss des neuen <em>generational mode<\/em>, der die meisten Anwendungen sp\u00fcrbar performanter machen sollte.<\/li>\n\n\n\n<li>Au\u00dferdem wurde gro\u00df aufger\u00e4umt: Die seit Ewigkeiten als <em>deprecated<\/em> markierten Methoden <code>Thread.suspend()<\/code>, <code>Thread.resume()<\/code>, <code>ThreadGroup.suspend()<\/code>, <code>ThreadGroup.resume()<\/code> und <code>ThreadGroup.stop()<\/code> wurden in Java 23 endlich entfernt. Alle <code>Unsafe<\/code>-Methoden f\u00fcr Speicherzugriffe wurden als <em>deprecated for removal<\/em> markiert.<\/li>\n<\/ul>\n\n\n\n<p>Diverse sonstige \u00c4nderungen runden wie immer das Release ab. Das aktuelle Java-23-Release kannst du <a href=\"https:\/\/jdk.java.net\/23\/\" target=\"_blank\" rel=\"noopener\">hier<\/a> herunterladen.<\/p>\n\n\n\n<p>Welche der neuen Java 23-Features findest du am spannendsten? Welches Feature vermisst du? Teile deine Meinung in den Kommentaren!<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neue Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>Alle Java 23-Features mit Beispielen: Primitive Type Patterns; Markdown in JavaDoc; Module importieren; `print()`, `println()` und `readln()` ohne `System.in` und `System.out`; Feld-Zuweisungen im Konstruktor vor super() \u2013 und mehr!<\/p>\n","protected":false},"author":1,"featured_media":40674,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"","_seopress_titles_title":"","_seopress_titles_desc":"Alle Java 23-Features mit Beispielen: Primitive Type Patterns, Markdown, Module importieren, Feld-Zuweisungen im Konstruktor vor super() \u2013 und 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":46185,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-40593","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\/2024\/05\/java-23-features.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-features.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2024\/05\/java-23-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":"Alle Java 23-Features mit Beispielen: Primitive Type Patterns; Markdown in JavaDoc; Module importieren; `print()`, `println()` und `readln()` ohne `System.in` und `System.out`; Feld-Zuweisungen im Konstruktor vor super() \u2013 und mehr!","public_identification_id":"1739ff9e60d745139571aa056067e6bb","private_identification_id":"496561a53bdb4424a35d4db851c3de53","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/40593","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=40593"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/40593\/revisions"}],"predecessor-version":[{"id":54128,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/40593\/revisions\/54128"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/40674"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=40593"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=40593"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=40593"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}