{"id":26706,"date":"2022-03-22T08:00:00","date_gmt":"2022-03-22T07:00:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=26706"},"modified":"2025-12-04T11:52:53","modified_gmt":"2025-12-04T10:52:53","slug":"java-18-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-18-features\/","title":{"rendered":"Java 18 Features (mit Beispielen)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Java 18, ver\u00f6ffentlicht am 22. M\u00e4rz 2022, ist das erste \"Zwischen-Release\" nach dem letzten Long-Term-Support (LTS)-Release, Java 17.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Der Umfang an Erweiterungen in Java 18 ist mit neun umgesetzten JEPs gegen\u00fcber den vorherigen Releases deutlich zur\u00fcckgegangen. Nach dem LTS-Release Java 17 sei den JDK-Entwicklern eine kleine Verschnaufspause geg\u00f6nnt ;-)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wie immer verwende ich die englischen Bezeichnungen der JEPs. Diese auf deutsch zu \u00fcbersetzen w\u00fcrde eher verwirren als einen Mehrwert zu bringen.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"utf-8-by-default\">UTF-8 by Default<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Seit langem m\u00fcssen wir Java-Entwicklerinnen und -Entwickler mit der Tatsache umgehen, dass der Java-Standardzeichensatz je nach Betriebssystem und Spracheinstellungen unterschiedlich ist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das \u00e4ndert sich mit Java 18 :-)<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Das Problem<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Der Java-Standardzeichensatz bestimmt bei zahlreichen Methoden der JDK-Klassenbibliothek, wie Zeichenfolgen in Bytes umgewandelt werden und umgekehrt (z. B. beim Schreiben und Lesen einer Textdatei). Dazu geh\u00f6ren z. B.: <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>die Konstruktoren von <code>FileReader<\/code>, <code>FileWriter<\/code>, <code>InputStreamReader<\/code>, <code>OutputStreamWriter<\/code>, <\/li>\n\n\n\n<li>die Konstruktoren von <code>Formatter<\/code> und <code>Scanner<\/code>,<\/li>\n\n\n\n<li>die statischen Methoden <code>URLEncoder.encode()<\/code> und <code>URLDecoder.decode()<\/code>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Das kann zu unvorhergesehenem Verhalten f\u00fchren, wenn eine Anwendung in einer Umgebung entwickelt und getestet \u2013 und dann in einer anderen Umgebung (in der sich Java f\u00fcr einen anderen Standardzeichensatz entscheidet) ausgef\u00fchrt wird.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fchren wir z. B. den folgenden Code unter Linux oder macOS aus (der japanische Text hei\u00dft laut Google Translate \"Happy Coding!\"):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> (FileWriter fw = <span class=\"hljs-keyword\">new<\/span> FileWriter(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>);\n    BufferedWriter bw = <span class=\"hljs-keyword\">new<\/span> BufferedWriter(fw)) {\n  bw.write(<span class=\"hljs-string\">\"\u30cf\u30c3\u30d4\u30fc\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\uff01\"<\/span>);\n}<\/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 class=\"wp-block-paragraph\">... und laden diese Datei dann mit folgendem Code unter Windows:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> (FileReader fr = <span class=\"hljs-keyword\">new<\/span> FileReader(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>);\n    BufferedReader br = <span class=\"hljs-keyword\">new<\/span> BufferedReader(fr)) {\n  String line = br.readLine();\n  System.out.println(line);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Dann wird folgendes angezeigt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">\u00e3\u0192?\u00e3\u0192\u0192\u00e3\u0192\u201d\u00e3\u0192\u00bc\u00e3\u201a\u00b3\u00e3\u0192\u00bc\u00e3\u0192\u2021\u00e3\u201a\u00a3\u00e3\u0192\u00b3\u00e3\u201a\u00b0\u00ef\u00bc?<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Das liegt daran, dass Linux und macOS die Datei im UTF-8-Format speichern und Windows sie im Windows-1252-Format versucht zu lesen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Das Problem \u2013 Stufe zwei<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Noch chaotischer wird es dadurch, dass neuere Methoden der Klassenbibliothek den Standardzeichensatz <em>nicht<\/em> ber\u00fccksichtigen, sondern bei fehlender Angabe eines Zeichensatzes grunds\u00e4tzlich UTF-8 verwenden. Zu diesen Methoden geh\u00f6ren z. B. <code>Files.writeString()<\/code>, <code>Files.readString()<\/code>, <code>Files.newBufferedWriter()<\/code> und <code>Files.newBufferedReader()<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Starten wir einmal das folgende Programm, das den japanischen Text per <code>FileWriter<\/code> schreibt und direkt danach per <code>Files.readString()<\/code> wieder einliest:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> (FileWriter fw = <span class=\"hljs-keyword\">new<\/span> FileWriter(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>);\n    BufferedWriter bw = <span class=\"hljs-keyword\">new<\/span> BufferedWriter(fw)) {\n  bw.write(<span class=\"hljs-string\">\"\u30cf\u30c3\u30d4\u30fc\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\uff01\"<\/span>);\n}\n\nString text = Files.readString(Path.of(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>));\nSystem.out.println(text);<\/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 class=\"wp-block-paragraph\">Unter Linux\/macOS wird der korrekte japanische Text angezeigt. Unter Windows hingegen nur Fragezeichen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">???????????<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><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 class=\"wp-block-paragraph\">Das liegt daran, dass der <code>FileWriter<\/code> unter Windows die Datei mit dem Java-Standardzeichensatz Windows-1252 schreibt, <code>Files.readString()<\/code> die Datei aber als UTF-8 \u2013 unabh\u00e4ngig vom Standardzeichensatz \u2013 wieder einliest.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Bisherige L\u00f6sungsm\u00f6glichkeiten<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Um eine Anwendung gegen solche Fehler zu wappnen, gab es bisher zwei M\u00f6glichkeiten:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Angabe des Zeichensatzes beim Aufruf aller Methoden, welche Zeichenfolgen in Bytes umwandeln und umgekehrt.<\/li>\n\n\n\n<li>Setzen des Standardzeichensatzes per System Property \"file.encoding\".<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Die erste M\u00f6glichkeit f\u00fchrt zu einer Menge Code Duplication und ist somit unsch\u00f6n und fehleranf\u00e4llig:<\/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\">FileWriter fw = <span class=\"hljs-keyword\">new<\/span> FileWriter(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>, StandardCharsets.UTF_8);\n<span class=\"hljs-comment\">\/\/ ...<\/span>\nFileReader fr = <span class=\"hljs-keyword\">new<\/span> FileReader(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>, StandardCharsets.UTF_8);\n<span class=\"hljs-comment\">\/\/ ...<\/span>\nFiles.readString(Path.of(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>), StandardCharsets.UTF_8);<\/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 class=\"wp-block-paragraph\">Die Angabe der Zeichensatz-Parameter verhindert au\u00dferdem, dass wir Methodenreferenzen verwenden k\u00f6nnen, wie in folgendem Beispiel:<\/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\">Stream&lt;String&gt; encodedParams = ...\nStream&lt;String&gt; decodedParams = encodedParams.map(URLDecoder::decode);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Stattdessen m\u00fcssten wir schreiben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Stream&lt;String&gt; encodedParams = ...\nStream&lt;String&gt; decodedParams =\n    encodedParams.map(s -&gt; URLDecoder.decode(s, StandardCharsets.UTF_8));\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 class=\"wp-block-paragraph\">Die zweite M\u00f6glichkeit (System Property \"file.encoding\") war zum einen bis einschlie\u00dflich Java 17 nicht offiziell dokumentiert (s. <a rel=\"noopener\" href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/system-properties.html\" target=\"_blank\">Dokumentation der System Properties<\/a>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Zum anderen wird, wie oben erl\u00e4utert, der so festgelegte Zeichensatz nicht f\u00fcr alle API-Methoden verwendet. Die Variante ist also ebenfalls fehleranf\u00e4llig, wie wir an dem Beispiel von oben zeigen k\u00f6nnen:<\/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\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Jep400Example<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <span class=\"hljs-keyword\">throws<\/span> IOException <\/span>{\n    <span class=\"hljs-keyword\">try<\/span> (FileWriter fw = <span class=\"hljs-keyword\">new<\/span> FileWriter(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>);\n        BufferedWriter bw = <span class=\"hljs-keyword\">new<\/span> BufferedWriter(fw)) {\n      bw.write(<span class=\"hljs-string\">\"\u30cf\u30c3\u30d4\u30fc\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\uff01\"<\/span>);\n    }\n\n    String text = Files.readString(Path.of(<span class=\"hljs-string\">\"happy-coding.txt\"<\/span>));\n    System.out.println(text);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Lassen wir das Programm einmal mit Standard-Encoding US-ASCII laufen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java -Dfile.encoding=US-ASCII Jep400Example.java\n?????????????????????????????????<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><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 class=\"wp-block-paragraph\">Dabei kommt nur M\u00fcll heraus, da zwar <code>FileWriter<\/code> das eingestellte Standard-Encoding ber\u00fccksichtigt, <code>Files.readString()<\/code> es allerdings ignoriert und immer UTF-8 verwendet. Diese Variante funktioniert also nur dann zuverl\u00e4ssig, wenn einheitlich UTF-8 eingesetzt wird:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java -Dfile.encoding=UTF-8 Jep400Example.java\n\u30cf\u30c3\u30d4\u30fc\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\uff01<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><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<h4 class=\"wp-block-heading\">JEP 400 als Retter in der Not<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Per <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/400\" target=\"_blank\">JDK Enhancement Proposal 400<\/a> werden ab Java 18 die genannten Probleme \u2013 zumindest gr\u00f6\u00dftenteils \u2013 der Vergangenheit angeh\u00f6ren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das Standard-Encoding wird auf allen Betriebssystemen und unabh\u00e4ngig von den Gebiets- und Spracheinstellungen immer UTF-8 sein.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Au\u00dferdem wird die System Property \"file.encoding\" dokumentiert sein, womit wir sie legitim einsetzen k\u00f6nnen. Das sollten wir allerdings mit Bedacht tun. Denn an der Tatsache, dass die <code>Files<\/code>-Methoden das eingestellte Standard-Encoding ignorieren, wird sich auch durch JEP 400 nichts \u00e4ndern. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Laut <a href=\"https:\/\/openjdk.org:443\/jeps\/400#The-file-encoding-and-native-encoding-system-properties\" target=\"_blank\" rel=\"noopener\">Dokumentation<\/a> sollten ohnehin nur die Werte \"UTF-8\" und \"COMPAT\" verwendet werden, wobei UTF-8 f\u00fcr einheitliche Codierung sorgt und COMPAT das Verhalten von vor Java 18 simuliert. Alle anderen Werte f\u00fchren zu unspezifiziertem Verhalten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Gut m\u00f6glich, dass \"file.encoding\" in Zukunft \"deprecated\" und sp\u00e4ter komplett entfernt wird, um die verbleibende potentielle Fehlerquelle (Methoden die das Standard-Encoding respektieren vs. solche, die es nicht tun) zu eliminieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im besten Fall setzen wir \"-Dfile.encoding\" immer auf UTF-8 oder lassen es komplett weg.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Auslesen der Encodings zur Laufzeit<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Das aktuelle Standard-Encoding kann zur Laufzeit \u00fcber <code>Charset.defaultCharset()<\/code> oder die System Property \"file.encoding\" ausgelesen werden. Seit <a href=\"\/de\/java\/java-17-features\/#System_Property_for_Native_Character_Encoding_Name\">Java 17<\/a> gibt es au\u00dferdem die System Property \"native.encoding\", \u00fcber die das Encoding ausgelesen werden kann, das \u2013 vor Java 18 \u2013 das Standard-Encoding w\u00e4re, wenn keines angegeben wird:<\/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\">System.out.println(<span class=\"hljs-string\">\"Default charset : \"<\/span> + Charset.defaultCharset());\nSystem.out.println(<span class=\"hljs-string\">\"file.encoding   : \"<\/span> + System.getProperty(<span class=\"hljs-string\">\"file.encoding\"<\/span>));\nSystem.out.println(<span class=\"hljs-string\">\"native.encoding : \"<\/span> + System.getProperty(<span class=\"hljs-string\">\"native.encoding\"<\/span>));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Ohne Angabe von <code>-Dfile.encoding<\/code> gibt das Programm unter Linux und macOS unter Java 17 und Java 18 das Folgende aus:<\/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\">Default charset : UTF-8\nfile.encoding   : UTF-8\nnative.encoding : UTF-8<\/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 class=\"wp-block-paragraph\">Unter Windows und Java 17 lautet die Ausgabe wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Default charset : windows-1252\nfile.encoding   : Cp1252\nnative.encoding : Cp1252<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><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 class=\"wp-block-paragraph\">Und unter Windows und Java 18:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Default charset : UTF-8\nfile.encoding   : UTF-8\nnative.encoding : Cp1252<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Das native Encoding unter Windows bleibt also gleich, das Standard-Encoding hingegen \u00e4ndert sich entsprechend dieses JEPs auf UTF-8.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Der bisherige \"default\"-Zeichensatz<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn wir das kleine Programm von oben unter Linux oder macOS und Java 17 mit dem Parameter <code style=\"white-space: nowrap\">-Dfile.encoding=default<\/code> aufrufen, bekommen wir die folgende Ausgabe:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Default charset : US-ASCII\nfile.encoding   : default\nnative.encoding : UTF-8<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><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 class=\"wp-block-paragraph\">Das liegt daran, dass der Name \"default\" bisher als Alias f\u00fcr das Encoding \"US-ASCII\" verwendet werden durfte.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unter Java 18 wird das ge\u00e4ndert: \"default\" wird nicht mehr erkannt; die Ausgabe sieht wie folgt aus:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Default charset : UTF-8\nfile.encoding   : default\nnative.encoding : UTF-8<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Als System Property \"file.encoding\" wird \"default\" zwar noch ausgegeben \u2013 an der Stelle w\u00fcrden wir aber auch jede andere ung\u00fcltige Eingabe sehen. Der Default-Zeichensatz ist bei einer ung\u00fcltigen \"file.encoding\"-Eingabe immer UTF-8 ab Java 18 bzw. entspricht dem nativen Encoding bis Java 17.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"charset-forname-taking-fallback-default-value\">Charset.forName() Taking Fallback Default Value<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Nicht Teil des o. g. JEPs und auch in keinem anderen JEP definiert ist die neue Methode <code>Charset.forName(String charsetName, Charset fallback)<\/code>. Diese gibt bei unbekanntem Zeichensatz-Namen oder nicht unterst\u00fctztem Zeichensatz den angegebenen Fallback-Wert zur\u00fcck anstatt eine <code>IllegalCharsetNameException<\/code> oder eine <code>UnsupportedCharsetException<\/code> zu werfen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"simple-web-server\">Simple Web Server<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Fast alle modernen Programmiersprachen bieten die M\u00f6glichkeit, einen rudiment\u00e4ren HTTP-Server hochzufahren, z. B. um schnell einige Webfunktionen zu testen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a href=\"https:\/\/openjdk.org:443\/jeps\/408\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 408<\/a> bietet auch Java ab Version 18 diese M\u00f6glichkeit.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Der einfachste Weg den mitgelieferten Webserver zu starten ist das Kommando <code>jwebserver<\/code>. Es startet den Server auf localhost:8000 und liefert dort einen Datei-Browser f\u00fcr das aktuelle Verzeichnis:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ jwebserver\nBinding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".\nServing \/home\/sven and subdirectories on 127.0.0.1 port 8000\nURL http:\/\/127.0.0.1:8000\/<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><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 class=\"wp-block-paragraph\">Wie angezeigt, kannst du mit dem Parameter <code>-b<\/code> die IP-Adresse angeben, auf der der Webserver h\u00f6ren soll. Mit <code>-p<\/code> kannst du den Port \u00e4ndern und mit <code>-d<\/code> das Verzeichnis, das der Server ausliefern soll. Mit <code>-o<\/code> kannst du die Logausgaben konfigurieren. Also z. B.:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ jwebserver -b 127.0.0.100 -p 4444 -d \/tmp -o verbose\nServing \/tmp and subdirectories on 127.0.0.100 port 4444\nURL http:\/\/127.0.0.100:4444\/<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><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 class=\"wp-block-paragraph\">Eine Liste der Optionen mit Erkl\u00e4rungen bekommst du mit <code>jwebserver -h<\/code> angezeigt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Funktionsumfang<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Der Webserver ist sehr rudiment\u00e4r und hat folgende Einschr\u00e4nkungen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Das einzig unterst\u00fctzte Protokoll ist HTTP\/1.1.<\/li>\n\n\n\n<li>HTTPS wird nicht angeboten.<\/li>\n\n\n\n<li>Erlaubt sind nur die HTTP-Methoden GET und HEAD.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Java-API: SimpleFileServer<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><code>jwebserver<\/code> ist kein eigenst\u00e4ndiges Tool, sondern lediglich ein Wrapper, der folgendes aufruft:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>java -m jdk.httpserver<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dadurch wird die <code>main<\/code>-Methode der Klasse <code>sun.net.httpserver.simpleserver.Main<\/code> des Moduls <code>jdk.httpserver<\/code> aufgerufen. Diese ruft <code>SimpleFileServerImpl.start(\u2026)<\/code> auf. Dieser Starter wiederum wertet die Kommandozeilen-Parameter aus und erzeugt schlie\u00dflich den eigentlichen Server mit <code>SimpleFileServer.createFileServer(\u2026)<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mit dieser Methode kannst du auch per Java-Code einen Server starten:<\/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\">HttpServer server =\n    SimpleFileServer.createFileServer(\n        <span class=\"hljs-keyword\">new<\/span> InetSocketAddress(<span class=\"hljs-number\">8080<\/span>), Path.of(<span class=\"hljs-string\">\"tmp\"<\/span>), OutputLevel.INFO);\nserver.start();<\/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 class=\"wp-block-paragraph\">\u00dcber die Java-API kannst du den Webserver erweitern, z. B. kannst du bestimmte Verzeichnisse des Dateisystems \u00fcber andere HTTP-Pfade erreichbar machen und den Server um eigene Handler f\u00fcr bestimmte Pfade und HTTP-Methoden (z. B. PUT) erweitern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein vollst\u00e4ndiges Tutorial w\u00fcrde den Rahmen dieses Artikels sprengen. Weitere Details findest du in den <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/408#API\" target=\"_blank\">Abschnitten \"API\" und \"Enhanced request handling\" im JEP<\/a>.<\/p>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"code-snippets-in-java-api-documentation\">Code Snippets in Java API Documentation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn wir bisher mehrzeilige Code-Schnipsel in JavaDoc integrieren wollten, mussten wir das recht umst\u00e4ndlich \u00fcber <code>&lt;pre&gt;\u2026&lt;\/pre&gt;<\/code> ggf. in Kombination mit <code>{@code \u2026 }<\/code> machen. Dabei mussten wir auf zwei Dinge achten:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Zwischen <code>&lt;pre&gt;<\/code> und Code sowie zwischen Code und <code>&lt;\/pre&gt;<\/code> d\u00fcrfen keine Zeilenumbr\u00fcche erfolgen.<\/li>\n\n\n\n<li>Der Code beginnt direkt hinter den Sternchen; d. h. wenn zwischen Sternchen und Code Leerzeichen stehen, landen diese auch im JavaDoc. Der Code muss also um ein Zeichen nach links verschoben sein gegen\u00fcber dem restlichen Text im JavaDoc-Kommentar.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Hier ein Beispiel mit <code>&lt;pre&gt;<\/code>:<\/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-comment\">\/**\n * How to write a text file with Java 7:\n *\n * &lt;pre&gt;&lt;b&gt;try&lt;\/b&gt; (BufferedWriter writer = Files.&lt;i&gt;newBufferedWriter&lt;\/i&gt;(path)) {\n *  writer.write(text);\n *}&lt;\/pre&gt;\n *\/<\/span><\/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 class=\"wp-block-paragraph\">Und eines mit <code>&lt;pre&gt;<\/code> und <code>{@code \u2026 }<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-comment\">\/**\n * How to write a text file with Java 7:\n *\n * &lt;pre&gt;{<span class=\"hljs-doctag\">@code<\/span> try (BufferedWriter writer = Files.newBufferedWriter(path)) {\n *  writer.write(text);\n *}}&lt;\/pre&gt;\n *\/<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Der Unterschied zwischen beiden Varianten ist, dass wir in der ersten Variante den Code mit HTML-Tags wie z. B. <code>&lt;b&gt;<\/code> und <code>&lt;i&gt;<\/code> formatieren k\u00f6nnen, w\u00e4hrend in der zweiten Variante solche Tags nicht ausgewertet, sondern dargestellt werden w\u00fcrden.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Das @snippet-Tag in Java 18<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/413\" target=\"_blank\">JDK Enhancement Proposal 413<\/a> erweitert die JavaDoc-Syntax um das <code>@snippet<\/code>-Tag, das speziell f\u00fcr die Darstellung von Quellcode entwickelt wurde. Mit dem <code>@snippet<\/code>-Tag k\u00f6nnen wir den Kommentar wie folgt schreiben:<\/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-comment\">\/**\n * How to write a text file with Java 7:\n *\n * {<span class=\"hljs-doctag\">@snippet<\/span> :\n * try (BufferedWriter writer = Files.newBufferedWriter(path)) {\n *   writer.write(text);\n * }\n * }\n *\/<\/span><\/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 class=\"wp-block-paragraph\">Wir k\u00f6nnen au\u00dferdem Teile des Codes mit <code>@highlight<\/code> hervorheben, z. B. alle Vorkomnisse von \"text\" innerhalb der zweiten Codezeile:<\/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-comment\">\/**\n * {<span class=\"hljs-doctag\">@snippet<\/span> :\n * try (BufferedWriter writer = Files.newBufferedWriter(path)) {\n *   writer.write(text);  \/\/ <span class=\"hljs-doctag\">@highlight<\/span> substring=\"text\"\n * }\n * }\n *\/<\/span><\/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 class=\"wp-block-paragraph\">Das folgende Beispiel markiert innerhalb des mit  <code>@highlight region<\/code> und <code>@end<\/code> gekennzeichneten Blocks alle W\u00f6rter, die mit \"write\" beginnen. Mit <code>type=\"\u2026\"<\/code> k\u00f6nnen wir au\u00dferdem die Art der Hervorhebung festlegen: <code>bold<\/code>, <code>italic<\/code> or <code>highlighted<\/code> (farblich hinterlegt).<\/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-comment\">\/**\n * {<span class=\"hljs-doctag\">@snippet<\/span> :\n * \/\/ <span class=\"hljs-doctag\">@highlight<\/span> region regex=\"bwrite.*?b\" type=\"highlighted\"\n * try (BufferedWriter writer = Files.newBufferedWriter(path)) {\n *   writer.write(text);                                          \n * }\n * \/\/ <span class=\"hljs-doctag\">@end<\/span>\n * }\n *\/<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Mit <code>@link<\/code> k\u00f6nnen wir einen Teil des Texts verlinken, z. B. <code>BufferedWriter<\/code> mit dessen JavaDoc:<\/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\">\/**\n * {<span class=\"hljs-doctag\">@snippet<\/span> :\n * \/\/ <span class=\"hljs-doctag\">@link<\/span> substring=\"BufferedWriter\" target=\"java.io.BufferedWriter\" :\n * try (BufferedWriter writer = Files.newBufferedWriter(path)) {\n *   writer.write(text);\n * }\n * }\n *\/<\/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 class=\"wp-block-paragraph\">Achtung: der Doppelpunkt am Ende der Zeile mit dem <code>@link<\/code>-Tag ist in diesem Fall wichtig. Er bedeutet, dass der Kommentar sich auf die n\u00e4chste Zeile bezieht. Wir k\u00f6nnten den Kommentar genauso an das Ende der folgenden Zeile schreiben, so wie im ersten <code>@highlight<\/code>-Beispiel \u2013 oder mit <code>@link region<\/code> und <code>@end<\/code> einen Bereich festlegen, innerhalb dessen alle Vorkommnisse von <code>BufferedWriter<\/code> verlinkt werden sollen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Snippets aus anderen Dateien integrieren<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Laut JEP soll es auch m\u00f6glich sein, auf markierten Code in einer anderen Datei zu verweisen:<\/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-comment\">\/**\n * How to write a text file with Java 7:\n *\n * {<span class=\"hljs-doctag\">@snippet<\/span> file=\"FileWriter.java\" region=\"writeFile\"}\n *\/<\/span><\/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 class=\"wp-block-paragraph\">In der Datei <code>FileWriter.java<\/code> w\u00fcrden wir den Code wie folgt markieren:<\/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\">\/\/ @start region=\"writeFile\"<\/span>\n<span class=\"hljs-keyword\">try<\/span> (BufferedWriter writer = Files.newBufferedWriter(path)) {\n  writer.write(text);\n}\n<span class=\"hljs-comment\">\/\/ @end<\/span><\/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 class=\"wp-block-paragraph\">Diese Variante f\u00fchrt allerdings mit dem aktuellen Early-Access-Release (Build 18-ea+29-2007) zu einer \"File not found\"-Fehlermeldung beim Aufruf des <code>javadoc<\/code>-Kommandos. Dieser JEP ist offenbar zum aktuellen Zeitpunkt noch nicht vollst\u00e4ndig implementiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das waren meiner Meinung nach die wichtigsten <code>@snippet<\/code>-Tags. Eine vollst\u00e4ndige Referenz findest du im <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/413#Snippet-tag-reference\" target=\"_blank\">JEP<\/a>. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"internet-address-resolution-spi\">Internet-Address Resolution SPI<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Um in Java zu einem Hostname die IP-Adresse(n) herauszufinden, k\u00f6nnen wir <code>InetAddress.getByName(\u2026)<\/code> oder <code>InetAddress.getAllByName(\u2026)<\/code> verwenden. Hier ein Beispiel:<\/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\">InetAddress&#091;] addresses = InetAddress.getAllByName(<span class=\"hljs-string\">\"www.happycoders.eu\"<\/span>);\nSystem.out.println(<span class=\"hljs-string\">\"addresses = \"<\/span> + Arrays.toString(addresses));\n<\/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 class=\"wp-block-paragraph\">Der Code gibt bei mir das Folgende aus (die Zeilenumbr\u00fcche habe ich der \u00dcbersichtlichkeit halber manuell eingef\u00fcgt):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">addresses = &#091;www.happycoders.eu\/104.26.15.71,\n             www.happycoders.eu\/172.67.71.232, \n             www.happycoders.eu\/104.26.14.71]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><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 class=\"wp-block-paragraph\">F\u00fcr Reverse Lookups (also das Aufl\u00f6sen einer IP-Adresse zu einem Hostnamen) gibt es die Methoden <code>InetAddress::getCanonicalHostName<\/code> und <code>InetAddress::getHostName<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Standardm\u00e4\u00dfig verwendet <code>InetAddress<\/code> den Resolver des Betriebssystems, d. h. in der Regel wird zun\u00e4chst die <code>hosts<\/code>-Datei konsultiert und danach die konfigurierten DNS-Server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Diese feste Verdrahtung hat ein paar Nachteile:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Es ist nicht m\u00f6glich innerhalb von Tests einen Hostnamen auf die URL eines gemockten Servers zu mappen.<\/li>\n\n\n\n<li>Neue Hostname-Lookup-Protokolle (wie DNS \u00fcber QUIC, TLS oder HTTPS) k\u00f6nnen nicht ohne weiteres in Java implementiert werden.<\/li>\n\n\n\n<li>Die aktuelle Implementierung f\u00fchrt zu einem blockierenden Betriebssystem-Aufruf. Das allein ist schon unsch\u00f6n, da dieser Aufruf teilweise lange dauern kann und nicht unterbrechbar ist. Beim Einsatz von <a href=\"\/de\/java\/virtual-threads\/\">virtuellen Threads<\/a> f\u00fchrt dies sogar soweit, dass der Betriebssystem-Thread w\u00e4hrenddessen keine anderen virtuellen Threads bedienen kann.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/418\" target=\"_blank\">JDK Enhancement Proposal 418<\/a> wird ein Service Provider Interface (SPI) eingef\u00fchrt, um den eingebauten Standard-Resolver der Plattform durch andere Resolver ersetzen zu k\u00f6nnen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Internet-Address Resolution SPI \/ JEP 418 \u2013 Beispiel<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Das folgende Beispiel zeigt, wie du einen einfachen Resolver implementierst und registriert, der jede Anfrage mit der IP-Adresse 127.0.0.1 beantwortet. Du findest den Code auch in diesem <a rel=\"noopener\" href=\"https:\/\/github.com\/SvenWoltmann\/internet-address-resolution-spi-jep-418-demo\" target=\"_blank\">GitHub-Repository<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wir schreiben zun\u00e4chst den Resolver, indem wir das in Java 18 eingef\u00fchrte Interface <code>java.net.spi.InetAddressResolver.InetAddressResolver<\/code> implementieren (Klasse <a rel=\"noopener\" href=\"https:\/\/github.com\/SvenWoltmann\/internet-address-resolution-spi-jep-418-demo\/blob\/main\/src\/eu\/happycoders\/jep418\/HappyCodersInetAddressResolver.java\" target=\"_blank\">HappyCodersInetAddressResolver in GitHub<\/a>):<\/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-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HappyCodersInetAddressResolver<\/span> <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">InetAddressResolver<\/span> <\/span>{\n  <span class=\"hljs-meta\">@Override<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Stream&lt;InetAddress&gt; <span class=\"hljs-title\">lookupByName<\/span><span class=\"hljs-params\">(String host, LookupPolicy lookupPolicy)<\/span>\n      <span class=\"hljs-keyword\">throws<\/span> UnknownHostException <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> Stream.of(InetAddress.getByAddress(<span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-keyword\">byte<\/span>&#091;] {<span class=\"hljs-number\">127<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">1<\/span>}));\n  }\n\n  <span class=\"hljs-meta\">@Override<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> String <span class=\"hljs-title\">lookupByAddress<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">byte<\/span>&#091;] addr)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> UnsupportedOperationException();\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 class=\"wp-block-paragraph\">Da ich hier nur das grunds\u00e4tzliche Prinzip vorstellen m\u00f6chte, habe ich den Resolver so einfach wie m\u00f6glich gehalten, und er unterst\u00fctzt auch keine Reverse Lookups.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Als zweites ben\u00f6tigen wir einen Resolver-Provider (Klasse <a href=\"https:\/\/github.com\/SvenWoltmann\/internet-address-resolution-spi-jep-418-demo\/blob\/main\/src\/eu\/happycoders\/jep418\/HappyCodersInetAddressResolverProvider.java\" target=\"_blank\" rel=\"noopener\">HappyCodersInetAddressResolverProvider in GitHub<\/a>):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HappyCodersInetAddressResolverProvider<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">InetAddressResolverProvider<\/span> <\/span>{\n  <span class=\"hljs-meta\">@Override<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> InetAddressResolver <span class=\"hljs-title\">get<\/span><span class=\"hljs-params\">(Configuration configuration)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> HappyCodersInetAddressResolver();\n  }\n\n  <span class=\"hljs-meta\">@Override<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> String <span class=\"hljs-title\">name<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"HappyCoders Internet Address Resolver Provider\"<\/span>;\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Der Provider erstellt in der <code>get()<\/code>-Methode eine neue Instanz des zuvor implementierten Resolvers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im dritten Schritt m\u00fcssen wir den Resolver registrieren. Dazu legen wir im Verzeichnis <code>META-INF\/services<\/code> eine Datei mit dem Namen <code>java.net.spi.InetAddressResolverProvider<\/code> und mit folgendem Inhalt an (<a rel=\"noopener\" href=\"https:\/\/github.com\/SvenWoltmann\/internet-address-resolution-spi-jep-418-demo\/blob\/main\/src\/META-INF\/services\/java.net.spi.InetAddressResolverProvider\" target=\"_blank\">Datei in GitHub<\/a>):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">eu.happycoders.jep416.HappyCodersInetAddressResolverProvider<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><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 class=\"wp-block-paragraph\">Jetzt f\u00fchren wir erneut den Code von oben aus (Klasse <a href=\"https:\/\/github.com\/SvenWoltmann\/internet-address-resolution-spi-jep-418-demo\/blob\/main\/src\/eu\/happycoders\/jep418\/Jep418Demo.java\" target=\"_blank\" rel=\"noopener\">Jep418Demo in GitHub<\/a>):<\/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\">InetAddress&#091;] addresses = InetAddress.getAllByName(<span class=\"hljs-string\">\"www.happycoders.eu\"<\/span>);\nSystem.out.println(<span class=\"hljs-string\">\"addresses = \"<\/span> + Arrays.toString(addresses));<\/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 class=\"wp-block-paragraph\">Die Ausgabe lautet nun:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">addresses = &#091;\/127.0.0.1]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><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 class=\"wp-block-paragraph\">Das ist genau die IP-Adresse, die wir in unserem Resolver zur\u00fcckgegeben haben.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"preview-und-incubator-features\">Preview- und Incubator-Features<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In den folgenden Abschnitten findest du Preview- und Incubator-Features, die wir bereits aus den vorangegangenen Releases kennen. Es handelt sich um Wiedervorlagen mit kleinen \u00c4nderungen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"pattern-matching-for-switch-second-preview\">Pattern Matching for switch (Second Preview)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\"Pattern Matching for switch\" wurde in <a href=\"\/de\/java\/java-17-features\/#Pattern_Matching_for_switch_Preview\">Java 17<\/a> erstmals vorgestellt und erm\u00f6glicht <code>switch<\/code>-Statements (und -Ausdr\u00fccke) wie z. B. das folgende (mehr dazu findest du im verlinkten Java-17-Artikel):<\/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\">switch<\/span> (obj) {\n  <span class=\"hljs-keyword\">case<\/span> String s &amp;&amp; s.length() &gt; <span class=\"hljs-number\">5<\/span> -&gt; System.out.println(s.toUpperCase());\n  <span class=\"hljs-keyword\">case<\/span> String s                   -&gt; System.out.println(s.toLowerCase());\n\n  <span class=\"hljs-keyword\">case<\/span> Integer i                  -&gt; System.out.println(i * i);\n\n  <span class=\"hljs-keyword\">default<\/span> -&gt; {}\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 class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/420\" target=\"_blank\">JDK Enhancement Proposal 420<\/a> wurden in Java 18 zwei \u00c4nderungen vorgenommen \u2013 eine in der Dominanzpr\u00fcfung und eine in der Vollst\u00e4ndigkeitsanalyse bei der Kombination mit versiegelten Typen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Verbesserung der Dominanzpr\u00fcfung<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Was Dominanzpr\u00fcfung ist, habe ich im oben verlinkten Artikel zu Java 17 beschrieben. In K\u00fcrze: der folgende Code f\u00fchrt zu einem Compilerfehler:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>Object obj = ...\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">switch<\/span> (obj) {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">case<\/span> String s                   -&gt; System.out.println(s.toLowerCase());\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">case<\/span> String s &amp;&amp; s.length() &gt; <span class=\"hljs-number\">5<\/span> -&gt; System.out.println(s.toUpperCase());\n<\/span><\/span><span class='shcb-loc'><span>  ...\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Der Grund daf\u00fcr ist, dass das Pattern in Zeile 3 das l\u00e4ngere Pattern aus Zeile 4 \"dominiert\": Wenn <code>obj<\/code> ein String ist, wird es durch das Pattern in Zeile 3 gematcht, egal wie lang der String ist. Es gibt also kein Objekt, das durch das Pattern in Zeile 4 gematcht wird.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein Fall wurde jedoch bisher nicht bedacht \u2013 und zwar die Kombination aus Konstante und Guarded Pattern (ein Pattern mit <code>&amp;&amp;<\/code>). So ist der folgende Code unter Java 17 noch erlaubt:<\/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 shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>String string = ...\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">switch<\/span> (string) {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">case<\/span> String s &amp;&amp; s.length() &gt; <span class=\"hljs-number\">5<\/span> -&gt; System.out.println(s.toUpperCase());\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"foobar\"<\/span>                   -&gt; System.out.println(<span class=\"hljs-string\">\"baz\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  ...\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/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 class=\"wp-block-paragraph\">Wenn <code>obj<\/code> gleich \"foobar\" ist, wird es allerdings nicht durch Zeile 4 gematcht, sondern bereits durch Zeile 3 (denn es ist ja auch l\u00e4nger als 5 Zeichen).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Da nicht erreichbarer Code offensichtlich nicht beabsichtigt ist, bekommen wir in Java 18 den folgenden Compiler-Fehler:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">java --enable-preview --source 18 SwitchTest.java\nSwitchTest.java:9: error: this case label is dominated by a preceding case label\n      case \"foobar\"                   -&gt; System.out.println(\"baz\");\n           ^<\/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<h4 class=\"wp-block-heading\">Bugfix in der Vollst\u00e4ndigkeitsanalyse mit Sealed Types<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Was Vollst\u00e4ndigkeitsanalyse ist, erf\u00e4hrst du im <a href=\"\/de\/java\/sealed-classes\/#Vollstandigkeitsanalyse_bei_Pattern_Matching_for_switch\">Artikel \u00fcber versiegelte Typen<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die \u00c4nderung in Java 18 erkl\u00e4re ich an folgender versiegelter Beispiel-Klassenhierarchie aus dem JEP:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-41\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">sealed <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">I<\/span>&lt;<span class=\"hljs-title\">T<\/span>&gt; <span class=\"hljs-title\">permits<\/span> <span class=\"hljs-title\">A<\/span>, <span class=\"hljs-title\">B<\/span> <\/span>{}\n<span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">A<\/span>&lt;<span class=\"hljs-title\">X<\/span>&gt; <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">I<\/span>&lt;<span class=\"hljs-title\">String<\/span>&gt; <\/span>{}\n<span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">B<\/span>&lt;<span class=\"hljs-title\">Y<\/span>&gt; <span class=\"hljs-keyword\">implements<\/span> <span class=\"hljs-title\">I<\/span>&lt;<span class=\"hljs-title\">Y<\/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\">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 class=\"wp-block-paragraph\">Der folgende Code ist nicht compilierbar:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-42\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">I&lt;Integer&gt; i = ...\n<span class=\"hljs-keyword\">switch<\/span> (i) {\n  <span class=\"hljs-keyword\">case<\/span> A&lt;Integer&gt; a -&gt; System.out.println(<span class=\"hljs-string\">\"It's an A\"<\/span>);  <span class=\"hljs-comment\">\/\/ not compilable<\/span>\n  <span class=\"hljs-keyword\">case<\/span> B&lt;Integer&gt; b -&gt; System.out.println(<span class=\"hljs-string\">\"It's a B\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-42\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Sowohl Java 17 als auch Java 18 erkennen, dass <code>I&lt;Integer&gt;<\/code> nicht nach <code>A&lt;Integer&gt;<\/code> konvertiert werden kann (da <code>A&lt;Integer&gt;<\/code> ein <code>I&lt;String&gt;<\/code> ist) und melden:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>incompatible types: I&lt;Integer&gt; cannot be converted to A&lt;Integer&gt;<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tats\u00e4chlich ist aufgrund der versiegelten Klassenhierarchie <code>B&lt;Integer&gt;<\/code> die einzige Klasse, die <code>I&lt;Integer&gt;<\/code> implementieren kann. Das <code>switch<\/code>-Statement ist also wie folgt vollst\u00e4ndig:<\/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\">I&lt;Integer&gt; i = ...\n<span class=\"hljs-keyword\">switch<\/span> (i) {\n  <span class=\"hljs-keyword\">case<\/span> B&lt;Integer&gt; b -&gt; System.out.println(<span class=\"hljs-string\">\"It's a B\"<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-43\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Java 17 meldet hier allerdings:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>the switch statement does not cover all possible input values<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das ist ein offensichtlicher Bug, der in Java 18 behoben wurde.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vector-api-third-incubator\">Vector API (Third Incubator)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Die Vector API wurde bereits in <a href=\"\/de\/java\/java-16-features\/#Vector_API_Incubator\">Java 16<\/a> und <a href=\"\/de\/java\/java-17-features\/#Vector_API_Second_Incubator\">Java 17<\/a> als Incubator-Feature vorgestellt. Dabei geht es nicht um die <code>java.util.Vector<\/code>-Klasse aus Java 1.0, sondern um Vektorrechnung im mathematischen Sinn und deren Abbildung auf moderne Single-Instruction-Multiple-Data-(SIMD)-Architekturen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/417\" target=\"_blank\">JDK Enhancement Proposal 417<\/a> wurde erneut die Leistung verbessert und der Support auf \"ARM Scalable Vector Extension\" \u2013 eine optionale Erweiterung der ARM64-Plattform \u2013 erweitert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inkubator-Stadium bedeutet, dass das Feature noch erhebliche \u00c4nderungen durchlaufen kann. Ich werde die Vector API ausf\u00fchrlicher vorstellen, sobald sie den Preview-Status erreicht hat.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"foreign-function-memory-api-second-incubator\">Foreign Function &amp; Memory API (Second Incubator)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Die Foreign Function &amp; Memory API entstand in <a href=\"\/de\/java\/java-17-features\/#Foreign_Function_Memory_API_Incubator\">Java 17<\/a> durch Kombination der \"Foreign Memory Access API\" und der \"Foreign Linker API\", die beide zuvor \u2013 jeweils einzeln \u2013 durch mehrere Incubator-Phasen liefen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die neue API wird in <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/panama\/\" target=\"_blank\">Project Panama<\/a> entwickelt und ist als Ersatz f\u00fcr JNI (Java Native Interface) vorgesehen, welches bereits seit Java 1.1 Teil der Plattform ist. JNI erm\u00f6glicht den Aufruf von C-Code aus Java heraus. Wer einmal mit JNI gearbeitet hat, wei\u00df: JNI ist \u00e4u\u00dferst kompliziert zu implementieren, fehleranf\u00e4llig und langsam.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ziel der neuen API ist es den Implementierungsaufwand um 90 % zu reduzieren und die Leistung der API um Faktor 4 bis 5 zu beschleunigen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/419\" target=\"_blank\">JDK Enhancement Proposal 419<\/a> wurden weitgehende \u00c4nderungen an der API vorgenommen. Im n\u00e4chsten Release, <a href=\"\/de\/java\/java-19-features\/#Foreign_Function_Memory_API_Preview\">Java 19<\/a>, wird die API das Preview-Stadium erreichen.<\/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 class=\"wp-block-paragraph\">Auch in Java 18 wurden wieder einige Features als \"deprecated for removal\" markiert oder komplett entfernt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecate-finalization-for-removal\">Deprecate Finalization for Removal<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Finalization existiert seit Java 1.0 und soll helfen Resource-Leaks zu vermeiden, indem Klassen eine <code>finalize()<\/code>-Methode implementieren k\u00f6nnen, in der sie vom Betriebssystem angeforderte Resourcen (wie Datei-Handles oder Nicht-Heap-Speicher) wieder freigeben k\u00f6nnen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die <code>finalize()<\/code>-Methode wird vom Garbage Collector aufgerufen, bevor er den Speicherplatz eines Objekts freigibt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das scheint eine sinnvolle L\u00f6sung zu sein. Es hat sich allerdings gezeigt, dass Finalization einige grundlegende, kritische M\u00e4ngel hat:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Performance:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Da nicht vorhersehbar ist, wann der Garbage Collector ein Objekt aufr\u00e4umt (und ob er das \u00fcberhaupt tut), kann es sein, dass \u2013 nachdem ein Objekt nicht mehr referenziert wird \u2013 es sehr lange dauert, bis dessen <code>finalize()<\/code>-Methode aufgerufen wird (oder dass sie <em>nie<\/em> aufgerufen wird).<\/li>\n\n\n\n<li>Wenn der Garbage Collector eine Full GC durchf\u00fchrt, kann es zu sp\u00fcrbaren Latenzen kommen, wenn viele der aufzur\u00e4umenden Objekte <code>finalize()<\/code>-Methoden haben.<\/li>\n\n\n\n<li>Die <code>finalize()<\/code>-Methode wird f\u00fcr <em>jede<\/em> Instanz einer Klasse aufgerufen, selbst wenn es eigentlich nicht n\u00f6tig w\u00e4re. Es gibt keine M\u00f6glichkeit in einzelnen Objekten festzulegen, dass diese keine Finalization ben\u00f6tigen.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Sicherheitsrisiken:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die <code>finalize()<\/code>-Methode kann beliebigen Code ausf\u00fchren, z. B. auch eine Referenz des zu l\u00f6schenden Objekts speichern. Somit wird der Garbage Collector es nicht aufr\u00e4umen. Wird die Referenz auf das Objekt sp\u00e4ter wieder entfernt und das Objekt durch den Garbage Collector gel\u00f6scht, wird die <code>finalize()<\/code>-Methode <em>nicht<\/em> erneut aufgerufen.<\/li>\n\n\n\n<li>Wenn der Konstruktor einer Klasse eine Exception wirft, liegt das Objekt zun\u00e4chst trotzdem auf dem Heap. Wenn der Garbage Collector es entfernt, ruft er dessen <code>finalize()<\/code>-Methode auf. Diese kann dann Operationen auf einem ggf. unvollst\u00e4ndig initialisierten Objekt ausf\u00fchren oder dieses im Objektgraphen speichern.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Fehleranf\u00e4lligkeit:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Eine <code>finalize()<\/code>-Methode sollte immer auch die <code>finalize()<\/code>-Methode der Elternklasse aufrufen. Der Compiler fordert dies allerdings nicht ein (im Gegensatz zum Konstruktor). Selbst wenn wir unseren eigenen Code fehlerfrei schreiben, k\u00f6nnte jemand anderes unsere Klasse erweitern, die <code>finalize()<\/code>-Methode \u00fcberschreiben ohne die \u00fcberschriebene Methode aufzurufen und damit ein Resource Leak verursachen.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Multithreading:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"color: initial;\">Die <\/span><code style=\"background-color: rgb(255, 255, 255); color: initial;\">finalize()<\/code><span style=\"color: initial;\">-Methode wird in einem unspezifizierten Thread aufgerufen, so dass die Thread-Sicherheit des gesamten Objekts sichergestellt werden muss \u2013 selbst in einer Anwendung, die eigentlich kein Multithreading nutzt.<\/span><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Alternativen zur Finalization<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Es existieren folgende Alternativen zur Finalization:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Das in Java 7 eingef\u00fchrte \"try-with-resources\" generiert f\u00fcr alle Klassen, die das <code>AutoCloseable<\/code>-Interface implementieren, automatisch einen <code>finally<\/code>-Block, in dem die entsprechenden <code>close()<\/code>-Methoden aufgerufen werden. G\u00e4ngige Tools f\u00fcr statische Codeanalyse finden und bem\u00e4ngeln Code, der <code>AutoCloseable<\/code>-Objekte nicht innerhalb von \"try-with-resources\"-Bl\u00f6cken erzeugt.<\/li>\n\n\n\n<li>Durch die in Java 9 eingef\u00fchrte <a rel=\"noopener\" href=\"https:\/\/docs.oracle.com\/javase\/9\/docs\/api\/java\/lang\/ref\/Cleaner.html\" target=\"_blank\">Cleaner-API<\/a> k\u00f6nnen sogenannte \"Cleaner Actions\" registriert werden. Diese werden aufgerufen, wenn ein Objekt nicht mehr erreichbar ist (nicht erst dann, wenn es aufger\u00e4umt wird). Cleaner Actions haben keinen Zugriff auf das Objekt selbst (k\u00f6nnen also auch keine Referenz darauf speichern); wir brauchen sie f\u00fcr ein Objekt nur dann zu registrieren, wenn dieses spezifische Objekt sie ben\u00f6tigt; und wir k\u00f6nnen selbst bestimmen, in welchem Thread sie aufgerufen werden.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Aus den o. g. Gr\u00fcnden und aufgrund der Verf\u00fcgbarkeit von hinreichenden Alternativen wurden die <code>finalize()<\/code>-Methoden in <code>Object<\/code> und zahlreichen weiteren Klassen der JDK-Klassenbibliothek bereits in Java 9 als \"deprecated\" markiert. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/421\" target=\"_blank\">JDK Enhancement Proposal 421<\/a> werden die Methoden in Java 18 als \"deprecated for removal\" markiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Weiterhin wird die VM-Option <code>--finalization=disabled<\/code> eingef\u00fchrt, welche die Finalization komplett deaktiviert. Damit k\u00f6nnen wir Applikationen testen, bevor wir sie auf eine zuk\u00fcnftige Java-Version aktualisieren, in der Finalization vollst\u00e4ndig entfernt wurde.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">JDK Flight Recorder Event for Finalization<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Nicht Teil des o. g. JEPs ist das neue Flight Recorder Event \"jdk.FinalizerStatistics\". Dieses ist standardm\u00e4\u00dfig aktiviert und protokolliert jede instantiierte Klasse mit einer nicht leeren <code>finalize()<\/code>-Methode. So kann man leicht diejenigen Klassen identifizieren, die noch einen Finalizer verwenden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn Finalization per <code>--finalization=disabled<\/code> deaktiviert ist, werden diese Events nicht getriggert.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"terminally-deprecate-thread-stop\">Terminally Deprecate Thread.stop<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>Thread.stop()<\/code> wird in Java 18 als \"deprecated for removal\" markiert \u2013 endlich, nachdem es bereits seit Java 1.2 \"deprecated\" ist. In einer der n\u00e4chsten Versionen wird es dann hoffentlich \u2013 zusammen mit <code>suspend()<\/code> und <code>resume()<\/code> sowie den korrespondierenden Methoden in <code>ThreadGroup<\/code> \u2013 komplett entfernt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(Zu dieser \u00c4nderung gibt es keinen JDK Enhancement Proposal.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"remove-the-legacy-plainsocketimpl-and-plaindatagramsocketimpl-implementation\">Remove the Legacy PlainSocketImpl and PlainDatagramSocketImpl Implementation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In <a href=\"\/de\/java\/java-13-features\/#Reimplement_the_Legacy_Socket_API\">Java 13<\/a> wurden die Socket API und in <a href=\"\/de\/java\/java-15-features\/#Reimplement_the_Legacy_DatagramSocket_API\">Java 15<\/a> die DatagramSocket API neu implementiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die alten Implementierungen konnten seither \u00fcber die System Properties <code>jdk.net.usePlainSocketImpl<\/code> bzw. <code>jdk.net.usePlainDatagramSocketImpl<\/code> reaktiviert werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 18 wurde der alte Code entfernt und die o. g. System Properties entfernt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(Zu dieser \u00c4nderung gibt es keinen JDK Enhancement Proposal.)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-18\">Sonstige \u00c4nderungen in Java 18<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In diesem Abschnitt findest du diejenigen \u00c4nderungen, mit denen du in der t\u00e4glichen Programmierarbeit eher selten in Ber\u00fchrung kommen wirst. Es schadet dennoch sicher nicht, sie einmal zu \u00fcberfliegen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"reimplement-core-reflection-with-method-handles\">Reimplement Core Reflection with Method Handles<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn du viel mit Java-Reflection zu tun hast, wirst du wissen, dass sprichtw\u00f6rtlich mehrere Wege nach Rom f\u00fchren. Um beispielsweise das private <code>value<\/code>-Feld eines Strings per Reflection auszulesen, gibt es zwei M\u00f6glichkeiten:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1. Per sogenannter \"Core Reflection\":<\/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\">Field field = String<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>.<span class=\"hljs-title\">getDeclaredField<\/span>(\"<span class=\"hljs-title\">value<\/span>\")<\/span>;\nfield.setAccessible(<span class=\"hljs-keyword\">true<\/span>);\n<span class=\"hljs-keyword\">byte<\/span>&#091;] value = (<span class=\"hljs-keyword\">byte<\/span>&#091;]) field.get(string);\n<\/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 class=\"wp-block-paragraph\">2. \u00dcber \"Method Handles\":<\/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\">VarHandle handle =\n    MethodHandles.privateLookupIn(String<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>, <span class=\"hljs-title\">MethodHandles<\/span>.<span class=\"hljs-title\">lookup<\/span>())\n        .<span class=\"hljs-title\">findVarHandle<\/span>(<span class=\"hljs-title\">String<\/span>.<span class=\"hljs-title\">class<\/span>, \"<span class=\"hljs-title\">value<\/span>\", <span class=\"hljs-title\">byte<\/span>&#091;].<span class=\"hljs-title\">class<\/span>)<\/span>;\n<span class=\"hljs-keyword\">byte<\/span>&#091;] value = (<span class=\"hljs-keyword\">byte<\/span>&#091;]) handle.get(string);\n<\/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 class=\"wp-block-paragraph\">(Wichtig: Seit Java 16 musst du bei beiden Varianten das Paket <code>java.lang<\/code> aus dem Modul <code>java.base<\/code> f\u00fcr das aufrufende Modul \u00f6ffnen, z. B. per VM-Option <code>--add-opens java.base\/java.lang=ALL-UNNAMED<\/code>.)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Es gibt noch eine dritte Form, die wir nicht direkt sehen k\u00f6nnen: Core Reflection verwendet f\u00fcr die ersten paar Aufrufe nach dem Start der JVM zus\u00e4tzliche native JVM-Methoden und beginnt erst nach einer Weile damit den Java-Bytecode der Reflection-Aufrufe zu compilieren und zu optimieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Alle drei Varianten zu maintainen bedeutet einen erheblichen Aufwand f\u00fcr die JDK-Entwickler. Daher wurde im Rahmen von <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/416\" target=\"_blank\">JDK Enhancement Proposal 416<\/a> entschieden den Code der Reflection-Klassen <code>java.lang.reflect.Method<\/code>, <code>Field<\/code> und <code>Constructor<\/code> auf Basis von Method Handles neu zu implementieren und somit den Entwicklungsaufwand zu reduzieren.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zgc-serialgc-parallelgc-support-string-deduplication\">ZGC \/ SerialGC \/ ParallelGC Support String Deduplication<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Seit Java 18 unterst\u00fctzen auch der in <a href=\"\/de\/java\/java-15-features\/#ZGC_A_Scalable_Low-Latency_Garbage_Collector\">Java 15<\/a> als produktionsreif ver\u00f6ffentlichte Z Garbage Collector sowie der serielle und der parallele Garbage Collector String Deduplication.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">String Deduplication bedeutet, dass der Garbage Collector Strings erkennt, deren <code>value<\/code>- und <code>coder<\/code>-Felder die gleichen Bytes enthalten. Der GC l\u00f6scht diese Byte-Arrays bis auf eines und l\u00e4sst alle String-Instanzen dieses eine Byte-Array referenzieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das hei\u00dft, es werden eigentlich nicht die Strings dedupliziert (wie der Name des Features impliziert), sondern nur deren Byte-Arrays. An den Identit\u00e4ten der String-Objekte selbst \u00e4ndert sich nichts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">String Deduplication ist standardm\u00e4\u00dfig deaktiviert (da es einen potentiellen <a href=\"\/de\/java\/deep-reflection-integer-string-modifizieren\/\">Angriffsvektor per Deep Reflection<\/a> darstellt) und muss per VM-Option <code>-XX:+UseStringDeduplication<\/code> explizit aktiviert werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(String Deduplication wurde erstmals mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/192\" target=\"_blank\">JDK Enhancement Proposal 192<\/a> in Java 8u20 f\u00fcr den G1 ver\u00f6ffentlicht. F\u00fcr den Einbau in den ZGC, den seriellen und den parallelen GC in Java 18 gibt es keinen separaten JEP.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"allow-g1-heap-regions-up-to-512mb\">Allow G1 Heap Regions up to 512MB<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Der G1 Garbage Collector bestimmt die Gr\u00f6\u00dfe der Heap-Regionen in der Regel automatisch. Je nach Heap-Gr\u00f6\u00dfe wird die Gr\u00f6\u00dfe der Regionen auf einen Wert zwischen 1 MB und 32 MB festgelegt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Per VM-Option <code>-XX:G1HeapRegionSize<\/code> kann die Gr\u00f6\u00dfe der Regionen auch manuell gesetzt werden. Auch hierbei waren bisher Gr\u00f6\u00dfen zwischen 1 MB und 32 MB erlaubt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 18 wird die maximale Gr\u00f6\u00dfe der Regionen auf 512 MB erh\u00f6ht. Dies soll insbesondere die Heap-Fragmentierung bei sehr gro\u00dfen Objekten reduzieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die \u00c4nderung bezieht sich nur auf das manuelle Festlegen der Regionengr\u00f6\u00dfe. Bei der automatischen Bestimmung durch die JVM (also ohne Angabe der VM-Option) bleibt die maximale Gr\u00f6\u00dfe bei 32 GB.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(Zu dieser \u00c4nderung gibt es keinen JDK Enhancement Proposal.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-18\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 18<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Neben den in diesem Artikel pr\u00e4sentierten JDK Enhancement Proposals und \u00c4nderungen an den Klassenbibliotheken gibt es noch weitere \u00c4nderungen (z. B. an den Kryptographie-Modulen), die den Rahmen dieses Artikels sprengen w\u00fcrden. Eine vollst\u00e4ndige Liste findest du in den <a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/18all-relnotes.html\" target=\"_blank\" rel=\"noopener\">JDK 18 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 class=\"wp-block-paragraph\">Mit Java 18 beginnt der n\u00e4chste Zyklus von Non-LTS-Releases \u2013 bis voraussichtlich im September 2023 mit <a href=\"\/de\/java\/java-21-features\/\">Java 21<\/a> die n\u00e4chste LTS-Version ver\u00f6ffentlicht wird. Wer mitgerechnet hat, stellt fest: Zwischen Java 11 und Java 17 lagen f\u00fcnf Non-LTS-Releases und drei Jahre \u2013 zwischen Java 17 und 21 werden nur drei Non-LTS-Releases und zwei Jahre liegen. Oracle hat n\u00e4mlich kurz vor dem Release von Java 17 <a rel=\"noopener\" href=\"https:\/\/blogs.oracle.com\/java\/moving-the-jdk-to-a-two-year-lts-cadence\" target=\"_blank\">angek\u00fcndigt den Release-Zyklus zu verk\u00fcrzen<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Releases werden deshalb nicht voller gepackt werden als bisher. Tats\u00e4chlich ist Java 18 recht \u00fcbersichtlich und enth\u00e4lt seit langem keine \u00c4nderung an der Sprache selbst (nach zahlreichen Spracherweiterungen wie <a href=\"\/de\/java\/java-records\/\">Records<\/a> und <a href=\"\/de\/java\/sealed-classes\/\">Sealed Classes<\/a>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die wichtigsten \u00c4nderungen von Java 18 sind:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>UTF-8 wird in Zukunft auf allen Betriebssystemen und unabh\u00e4ngig von Sprach- und Gebietseinstellungen der Standard-Zeichensatz sein.<\/li>\n\n\n\n<li>Per <code>jwebserver<\/code>-Kommando (oder mit der <code>SimpleFileServer<\/code>-Klasse) k\u00f6nnen wir schnell einen rudiment\u00e4ren Webserver starten.<\/li>\n\n\n\n<li>Mit dem <code>@snippet<\/code>-Tag bekommen wir ein m\u00e4chtiges Werkzeug, um Quellcode-Schnipsel in unsere JavaDoc-Dokumentation zu integrieren.<\/li>\n\n\n\n<li>Mit dem \"Internet-Address Resolution SPI\" k\u00f6nnen wir den Standard-Resolver f\u00fcr IP-Adressen ersetzen, was insbesondere in Tests hilfreich ist.<\/li>\n\n\n\n<li>Die Preview- und Incubator Features \"Pattern Matching for switch\", \"Vector API\" und \"Foreign Function &amp; Memory API\" wurden in die jeweils n\u00e4chste Preview- bzw. Incubator-Runde geschickt.<\/li>\n\n\n\n<li>Finalization und <code>Thread.stop()<\/code> wurden als \"deprecated for removal\" markiert.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Diverse sonstige \u00c4nderungen runden wie immer das Release ab. Java 18 kannst du <a rel=\"noopener\" href=\"https:\/\/jdk.java.net\/18\/\" target=\"_blank\">hier<\/a> herunterladen.<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neuen Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>Alle neuen Features von Java 18 mit Beispielen: UTF-8 als Standard-Zeichensatz, @snippet-Tag f\u00fcr Code-Schnipsel in JavaDoc, jwebserver, Internet-Address Resolution SPI und mehr\u2026<\/p>\n","protected":false},"author":1,"featured_media":34260,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"Die neuen Features von Java 18 mit Beispielen: UTF-8 als Standard, @snippet-Tag in JavaDoc, jwebserver, Internet-Address Resolution SPI + mehr\u2026","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"none","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"both","_seopress_redirections_param":"","_seopress_redirections_type":301,"_seopress_analysis_target_kw":"java 18,java 18 features","_seopress_news_disabled":"","_seopress_video_disabled":"","_seopress_video":[],"_seopress_pro_schemas_manual":[{"_seopress_pro_rich_snippets_type":"none"}],"_seopress_pro_rich_snippets_disable_all":"","_seopress_pro_rich_snippets_disable":[],"_seopress_pro_schemas":[],"_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":36724,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-26706","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java-versionen"],"uagb_featured_image_src":{"full":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-features.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/03\/java-18-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 neuen Features von Java 18 mit Beispielen: UTF-8 als Standard-Zeichensatz, @snippet-Tag f\u00fcr Code-Schnipsel in JavaDoc, jwebserver, Internet-Address Resolution SPI und mehr\u2026","public_identification_id":"2695b5817f7d4c8dbda8d9b1d596bb8f","private_identification_id":"8055e26e48e74f3ab0635762c313dc36","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/26706","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=26706"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/26706\/revisions"}],"predecessor-version":[{"id":54124,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/26706\/revisions\/54124"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34260"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=26706"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=26706"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=26706"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}