{"id":25819,"date":"2021-12-28T13:34:00","date_gmt":"2021-12-28T12:34:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=25819"},"modified":"2025-06-11T21:32:19","modified_gmt":"2025-06-11T19:32:19","slug":"java-17-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-17-features\/","title":{"rendered":"Java 17 Features (mit Beispielen)"},"content":{"rendered":"\n<p>Am 14. September 2021 war es endlich soweit: Nach den f\u00fcnf \"Zwischenversionen\" Java 12 bis 15, die jeweils nur f\u00fcr ein halbes Jahr maintained wurden, wurde das aktuelle Long-Term-Support (LTS) Release, Java 17, ver\u00f6ffentlicht.<\/p>\n\n\n\n<p>Oracle wird f\u00fcr Java 17 f\u00fcr mindestens f\u00fcnf Jahre, also bis September 2026, kostenlose Upgrades zur Verf\u00fcgung stellen \u2013 und bis September 2029 einen erweiterten, kostenpflichtigen Support.<\/p>\n\n\n\n<p>In Java 17 wurden 14 JDK Enhancement Proposals umgesetzt. Ich habe die \u00c4nderungen nach Relevanz f\u00fcr die t\u00e4gliche Programmierarbeit sortiert. Der Artikel beginnt mit Erweiterungen der Sprache und \u00c4nderungen am Modulsystem. Es folgen diverse Erweiterungen der JDK-Klassenbibliothek, Performance-Verbesserungen, neue Preview- und Incubator-Features, Deprecations und L\u00f6schungen und am Ende sonstige \u00c4nderungen, mit denen man in der t\u00e4glichen Arbeit eher selten in Kontakt kommt.<\/p>\n\n\n\n<p>Wie immer habe ich die englischen Bezeichnungen der JEPs und der sonstigen \u00c4nderungen verwendet. Eine \u00dcbersetzung ins Deutsche w\u00fcrde hier keinen Mehrwert bringen. <\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sealed-classes\">Sealed Classes<\/h2>\n\n\n\n<p>Die gro\u00dfe Neuerung in Java 17 (neben dem Long-Term-Support) sind versiegelte Klassen und Interfaces.<\/p>\n\n\n\n<p>Was versiegelte Klassen sind, wie sie genau funktionieren und warum wir sie brauchen, erkl\u00e4re ich aufgrund des Umfangs des Themas in einem separaten Artikel: <a href=\"\/de\/java\/sealed-classes\/\">Sealed Classes in Java<\/a><\/p>\n\n\n\n<p><em>(Sealed Classes wurden erstmals in <a href=\"\/de\/java\/java-15-features\/#Sealed_Classes_Preview\">Java 15<\/a> als Preview-Feature vorgestellt. In <a href=\"\/de\/java\/java-16-features\/#Sealed_Classes_Second_Preview\">Java 16<\/a> wurden drei kleine \u00c4nderungen ver\u00f6ffentlicht. Mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/409\" target=\"_blank\">JDK Enhancement Proposal 409<\/a> werden Sealed Classes in Java 17 ohne weitere \u00c4nderungen als produktionsreif deklariert.)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"strongly-encapsulate-jdk-internals\">Strongly Encapsulate JDK Internals<\/h2>\n\n\n\n<p>In Java 9 wurde das Modulsystem (<a href=\"https:\/\/openjdk.org:443\/projects\/jigsaw\/\" target=\"_blank\" rel=\"noopener\">Project Jigsaw<\/a>) eingef\u00fchrt, insbesondere um Code besser modularisieren zu k\u00f6nnen und um die Sicherheit der Java-Plattform zu erh\u00f6hen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vor-java-16-relaxed-strong-encapsulation\">Vor Java 16: Relaxed Strong Encapsulation<\/h3>\n\n\n\n<p>Bis Java 16 hatte dies nur wenige Auswirkungen auf existierenden Code, da die JDK-Entwickler f\u00fcr eine \u00dcbergangszeit den Modus \"Relaxed Strong Encapsulation\" bereitgestellt haben. <\/p>\n\n\n\n<p>Dieser erlaubte es ohne Konfigurations\u00e4nderung per Deep Reflection auf nicht-\u00f6ffentliche Klassen und Methoden von Paketen der JDK-Klassenbibliothek, die schon vor Java 9 existierten, zuzugreifen.<\/p>\n\n\n\n<p>Das folgende Beispiel extrahiert die Bytes eines String, indem es dessen privates Feld <code>value<\/code> ausliest:<\/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\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">EncapsulationTest<\/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> ReflectiveOperationException <\/span>{\n    <span class=\"hljs-keyword\">byte<\/span>&#091;] value = getValue(<span class=\"hljs-string\">\"Happy Coding!\"<\/span>);\n    System.out.println(Arrays.toString(value));\n  }\n\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">byte<\/span>&#091;] getValue(String string) <span class=\"hljs-keyword\">throws<\/span> ReflectiveOperationException {\n    Field VALUE = String<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>.<span class=\"hljs-title\">getDeclaredField<\/span>(\"<span class=\"hljs-title\">value<\/span>\")<\/span>;\n    VALUE.setAccessible(<span class=\"hljs-keyword\">true<\/span>);\n    <span class=\"hljs-keyword\">return<\/span> (<span class=\"hljs-keyword\">byte<\/span>&#091;]) VALUE.get(string);\n  }\n}\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>Wenn wir dieses Programm mit Java 9 bis 15 aufrufen, erhalten wir folgende Ausgabe:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java EncapsulationTest.java\nWARNING: An illegal reflective access operation has occurred\nWARNING: Illegal reflective access by EncapsulationTest (file:\/...\/EncapsulationTest.java) to field java.lang.String.value\nWARNING: Please consider reporting this to the maintainers of EncapsulationTest\nWARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations\nWARNING: All illegal access operations will be denied in a future release\n&#091;72, 97, 112, 112, 121, 32, 67, 111, 100, 105, 110, 103, 33]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Wir sehen zwar einige Warnungen, bekommen dann aber die gew\u00fcnschten Bytes angezeigt.<\/p>\n\n\n\n<p>Deep Reflection auf <em>neue<\/em> Pakete hingegen war standardm\u00e4\u00dfig nicht erlaubt und musste seit der Einf\u00fchrung des Modulsystems per \"--add-opens\" auf der Kommandozeile explizit erlaubt werden.<\/p>\n\n\n\n<p>Das folgende Beispiel versucht die Klasse <code>ConstantDescs<\/code> aus dem in Java 12 (also nach der Einf\u00fchrung des Modulsystems) hinzugekommenen Paket <code>java.lang.constant<\/code> \u00fcber deren privaten Constructor zu instanziieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Constructor&lt;ConstantDescs&gt; constructor = ConstantDescs<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>.<span class=\"hljs-title\">getDeclaredConstructor<\/span>()<\/span>;\nconstructor.setAccessible(<span class=\"hljs-keyword\">true<\/span>);\nConstantDescs constantDescs = constructor.newInstance();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Das Programm bricht mit folgender Fehlermeldung ab:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java ConstantDescsTest.java\nException in thread \"main\" java.lang.reflect.InaccessibleObjectException: Unable to make private java.lang.constant.ConstantDescs() accessible: module java.base does not \"opens java.lang.constant\" to unnamed module @6c3f5566\n        at java.base\/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:361)\n        at java.base\/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:301)\n        at java.base\/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:189)\n        at java.base\/java.lang.reflect.Constructor.setAccessible(Constructor.java:182)\n        at ConstantDescsTest.main(ConstantDescsTest.java:7)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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>Um das Programm lauff\u00e4hig zu machen, m\u00fcssen wir per <code>--add-opens<\/code> das neue Paket f\u00fcr Deep Reflection \u00f6ffnen:<\/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\">$ java --add-opens java.base\/java.lang.constant=ALL-UNNAMED ConstantDescsTest.java\n<\/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>Der Code l\u00e4uft dann fehlerfrei und ohne Warnungen durch.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"seit-java-16-standardmaessig-strong-encapsulation-optional-relaxed-strong-encapsulation\">Seit Java 16: Standardm\u00e4\u00dfig Strong Encapsulation + Optional Relaxed Strong Encapsulation<\/h3>\n\n\n\n<p>In <a href=\"\/de\/java\/java-16-features\/#Strongly_Encapsulate_JDK_Internals_by_Default\" data-type=\"URL\" data-id=\"\/de\/java\/java-16-features\/#Strongly_Encapsulate_JDK_Internals_by_Default\">Java 16<\/a> wurde der Standardmodus von \"Relaxed Strong Encapsulation\" auf \"Strong Encapsulation\" ge\u00e4ndert. Seither musste auch der Zugriff auf Pre-Java-9-Pakete explizit erlaubt werden.<\/p>\n\n\n\n<p>Wenn wir das erste Beispiel unter Java 16 ausf\u00fchren, ohne den Zugriff explizit zu erlauben, erhalten wir folgende Fehlermeldung:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java EncapsulationTest.java\nException in thread \"main\" java.lang.reflect.InaccessibleObjectException: Unable to make field private final byte&#091;] java.lang.String.value accessible: module java.base does not \"opens java.lang\" to unnamed module @62fdb4a6\n        at java.base\/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)\n        at java.base\/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)\n        at java.base\/java.lang.reflect.Field.checkCanSetAccessible(Field.java:177)\n        at java.base\/java.lang.reflect.Field.setAccessible(Field.java:171)\n        at EncapsulationTest.getValue(EncapsulationTest.java:12)\n        at EncapsulationTest.main(EncapsulationTest.java:6)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><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>Java 16 bot allerdings noch einen Workaround: Per VM-Option <code>--illegal-access=permit<\/code> konnte auf \"Relaxed Strong Encapsulation\" zur\u00fcckgeschaltet werden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java --illegal-access=permit EncapsulationTest.java\nJava HotSpot(TM) 64-Bit Server VM warning: Option --illegal-access is deprecated and will be removed in a future release.\nWARNING: An illegal reflective access operation has occurred\nWARNING: Illegal reflective access by EncapsulationTest (file:\/...\/EncapsulationTest.java) to field java.lang.String.value\nWARNING: Please consider reporting this to the maintainers of EncapsulationTest\nWARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations\nWARNING: All illegal access operations will be denied in a future release\n&#091;72, 97, 112, 112, 121, 32, 67, 111, 100, 105, 110, 103, 33]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"seit-java-17-ausschliesslich-strong-encapsulation\">Seit Java 17: Ausschlie\u00dflich Strong Encapsulation<\/h3>\n\n\n\n<p>Per <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/403\" target=\"_blank\">JDK Enhancement Proposal 403<\/a> wird diese M\u00f6glichkeit ab Java 17 entfernt. Die VM-Option <code style=\"white-space: nowrap\">--illegal-access<\/code> wurde mit einer Warnung versehen, und der Zugriff auf <code>String.value<\/code> ist standardm\u00e4\u00dfig nicht mehr m\u00f6glich:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">java --illegal-access=permit EncapsulationTest.java\nOpenJDK 64-Bit Server VM warning: Ignoring option --illegal-access=permit; support was removed in 17.0\nException in thread \"main\" java.lang.reflect.InaccessibleObjectException: Unable to make field private final byte&#091;] java.lang.String.value accessible: module java.base does not \"opens java.lang\" to unnamed module @3e77a1ed\n        at java.base\/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)\n        at java.base\/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)\n        at java.base\/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)\n        at java.base\/java.lang.reflect.Field.setAccessible(Field.java:172)\n        at EncapsulationTest.getValue(EncapsulationTest.java:12)\n        at EncapsulationTest.main(EncapsulationTest.java:6)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><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>Wer ab Java 17 Deep Reflection einsetzen will, muss dies nun explizit mit <code>--add-opens<\/code> erlauben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java --add-opens java.base\/java.lang=ALL-UNNAMED EncapsulationTest.java\n&#091;72, 97, 112, 112, 121, 32, 67, 111, 100, 105, 110, 103, 33]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><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>Das Programm l\u00e4uft, und wir sehen keine Warnungen mehr \u2013 die lange \u00dcbergangsphase seit Java 9 ist damit abgeschlossen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"add-java-time-instantsource\">Add java.time.InstantSource<\/h2>\n\n\n\n<p>Die Klasse <code>java.time.Clock<\/code> ist \u00e4u\u00dferst n\u00fctzlich, um Tests zu schreiben, die zeitabh\u00e4ngige Funktionalit\u00e4t \u00fcberpr\u00fcfen.<\/p>\n\n\n\n<p>Wenn <code>Clock<\/code> z. B. per Dependency Injection in die Anwendungsklassen injiziert wird, kann man diese in Tests mocken oder durch <code>Clock.fixed()<\/code> eine feste Uhrzeit f\u00fcr die Testausf\u00fchrung festlegen.<\/p>\n\n\n\n<p>Da <code>Clock<\/code> die Methode <code>getZone()<\/code> bereitstellt, muss man sich immer Gedanken dar\u00fcber machen, mit welcher konkreten Zeitzone man ein <code>Clock<\/code>-Objekt instanziiert.<\/p>\n\n\n\n<p>Um alternative, Zeitzonen-unabh\u00e4ngige Zeitquellen zu erm\u00f6glichen, wurde in Java 17 das Interface <code>java.time.InstantSource<\/code> aus <code>Clock<\/code> extrahiert, welches zum Abfragen der Zeit nur noch die Methoden <code>instant()<\/code> und <code>millis()<\/code> bereitstellt, wobei <code>millis()<\/code> bereits als Default-Methode implementiert ist.<\/p>\n\n\n\n<p>Die <code>Timer<\/code>-Klasse im folgenden Beispiel nutzt <code>InstantSource<\/code>, um die Start- und Endzeit der Ausf\u00fchrung eines <code>Runnable<\/code> festzustellen und daraus die Dauer der Ausf\u00fchrung zu berechnen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Timer<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> InstantSource instantSource;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">Timer<\/span><span class=\"hljs-params\">(InstantSource instantSource)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">this<\/span>.instantSource = instantSource;\n  }\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Duration <span class=\"hljs-title\">measure<\/span><span class=\"hljs-params\">(Runnable runnable)<\/span> <\/span>{\n    Instant start = instantSource.instant();\n    runnable.run();\n    Instant end = instantSource.instant();\n    <span class=\"hljs-keyword\">return<\/span> Duration.between(start, end);\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In Produktion k\u00f6nnen wir <code>Timer<\/code> mit der System-Uhr instanziieren (wobei wir uns mangels alternativer <code>InstantSource<\/code>-Implementierungen Gedanken um die Zeitzone machen m\u00fcssen \u2013 wir nehmen die Standardzeitzone des Systems):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Timer timer = <span class=\"hljs-keyword\">new<\/span> Timer(Clock.systemDefaultZone());<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Testen k\u00f6nnen wir die <code>measure()<\/code>-Methode, indem wir <code>InstantSource<\/code> mocken, deren <code>instant()<\/code>-Methode zwei feste Werte zur\u00fcckgeben lassen und den R\u00fcckgabewert von <code>measure()<\/code> mit der Differenz dieser Werte vergleichen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-meta\">@Test<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">shouldReturnDurationBetweenStartAndEnd<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n  InstantSource instantSource = mock(InstantSource<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>)<\/span>;\n  when(instantSource.instant())\n      .thenReturn(Instant.ofEpochMilli(<span class=\"hljs-number\">1_640_033_566_000L<\/span>))\n      .thenReturn(Instant.ofEpochMilli(<span class=\"hljs-number\">1_640_033_567_750L<\/span>));\n\n  Timer timer = <span class=\"hljs-keyword\">new<\/span> Timer(instantSource);\n  Duration duration = timer.measure(() -&gt; {});\n\n  assertThat(duration, is(Duration.ofMillis(<span class=\"hljs-number\">1_750<\/span>)));\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><em>F\u00fcr diese Erweiterung gibt es kein JDK Enhancement Proposal.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"hex-formatting-and-parsing-utility\">Hex Formatting and Parsing Utility<\/h2>\n\n\n\n<p>Um hexadezimale Zahlen auszugeben, konnten wir bisher die <code>toHexString()<\/code>-Methode der Klassen <code>Integer<\/code>, <code>Long<\/code>, <code>Float<\/code> und <code>Double<\/code> verwenden \u2013 oder <code>String.format()<\/code> einsetzen. Der folgende Code zeigt ein paar Beispiele:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">System.out.println(Integer.toHexString(<span class=\"hljs-number\">1_000<\/span>));\nSystem.out.println(Long.toHexString(<span class=\"hljs-number\">100_000_000_000L<\/span>));\nSystem.out.println(Float.toHexString(<span class=\"hljs-number\">3.14F<\/span>));\nSystem.out.println(Double.toHexString(<span class=\"hljs-number\">3.14159265359<\/span>));\n\nSystem.out.println(\n    <span class=\"hljs-string\">\"%x - %x - %a - %a\"<\/span>.formatted(<span class=\"hljs-number\">1_000<\/span>, <span class=\"hljs-number\">100_000_000_000L<\/span>, <span class=\"hljs-number\">3.14F<\/span>, <span class=\"hljs-number\">3.14159265359<\/span>));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Der Code f\u00fchrt zu folgender Ausgabe:<\/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\">3e8\n174876e800\n0x1.91eb86p1\n0x1.921fb54442eeap1\n3e8 - 174876e800 - 0x1.91eb86p1 - 0x1.921fb54442eeap1<\/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>Parsen konnten wir hexadezimale Zahlen mit den jeweiligen Pendants:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Integer.parseInt(<span class=\"hljs-string\">\"3e8\"<\/span>, <span class=\"hljs-number\">16<\/span>);\nLong.parseLong(<span class=\"hljs-string\">\"174876e800\"<\/span>, <span class=\"hljs-number\">16<\/span>);\nFloat.parseFloat(<span class=\"hljs-string\">\"0x1.91eb86p1\"<\/span>);\nDouble.parseDouble(<span class=\"hljs-string\">\"0x1.921fb54442eeap1\"<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Java 17 stellt die neue Klasse <code>java.util.HexFormat<\/code> zur Verf\u00fcgung, mit der Darstellen und Parsen hexadezimaler Zahlen \u00fcber eine einheitliche API abgebildet wird. <code>HexFormat<\/code> unterst\u00fctzt dabei alle primitiven Ganzzahlen (<code>int<\/code>, <code>byte<\/code>, <code>char<\/code>, <code>long<\/code>, <code>short<\/code>) sowie <code>byte<\/code>-Arrays \u2013 allerdings keine Flie\u00dfkommazahlen. <\/p>\n\n\n\n<p>Hier ein Beispiel f\u00fcr die Umwandlung in hexadezimale Zahlen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">HexFormat hexFormat = HexFormat.of();\n\nSystem.out.println(hexFormat.toHexDigits(<span class=\"hljs-string\">'A'<\/span>));\nSystem.out.println(hexFormat.toHexDigits((<span class=\"hljs-keyword\">byte<\/span>) <span class=\"hljs-number\">10<\/span>));\nSystem.out.println(hexFormat.toHexDigits((<span class=\"hljs-keyword\">short<\/span>) <span class=\"hljs-number\">1_000<\/span>));\nSystem.out.println(hexFormat.toHexDigits(<span class=\"hljs-number\">1_000_000<\/span>));\nSystem.out.println(hexFormat.toHexDigits(<span class=\"hljs-number\">100_000_000_000L<\/span>));\nSystem.out.println(hexFormat.formatHex(<span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-keyword\">byte<\/span>&#091;] {<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span>, <span class=\"hljs-number\">60<\/span>, <span class=\"hljs-number\">126<\/span>, -<span class=\"hljs-number\">1<\/span>}));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Ausgabe lautet:<\/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\">0041\n0a\n03e8\n000f4240\n000000174876e800\n0102033c7eff<\/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>Es f\u00e4llt auf, dass die Ausgabe jeweils mit vorangestellten Nullen erfolgt.<\/p>\n\n\n\n<p>Die Darstellung k\u00f6nnen wir z. B. wie folgt anpassen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">HexFormat hexFormat = HexFormat.ofDelimiter(<span class=\"hljs-string\">\" \"<\/span>).withPrefix(<span class=\"hljs-string\">\"0x\"<\/span>).withUpperCase();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<ul class=\"wp-block-list\">\n<li><code>ofDelimiter()<\/code> legt ein Trennzeichen f\u00fcr die Formatierung von Byte-Arrays fest.<\/li>\n\n\n\n<li><code>withPrefix()<\/code> definiert ein Prefix \u2013 allerdings nur f\u00fcr Byte-Arrays!<\/li>\n\n\n\n<li><code>withUpperCase()<\/code> schaltet die Ausgabe auf Gro\u00dfbuchstaben um.<\/li>\n<\/ul>\n\n\n\n<p>Die Ausgabe lautet nun:<\/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\">0041\n0A\n03E8\n000F4240\n000000174876E800\n0x01 0x02 0x03 0x3C 0x7E 0xFF<\/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>Die vorangestellten Nullen lassen sich nicht entfernen.<\/p>\n\n\n\n<p>Ganzzahlen k\u00f6nnen wir wie folgt parsen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">int<\/span> i = HexFormat.fromHexDigits(<span class=\"hljs-string\">\"F4240\"<\/span>);\n<span class=\"hljs-keyword\">long<\/span> l = HexFormat.fromHexDigitsToLong(<span class=\"hljs-string\">\"174876E800\"<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Entsprechende Methoden f\u00fcr <code>char<\/code>, <code>byte<\/code> und <code>short<\/code> existieren nicht.<\/p>\n\n\n\n<p>Byte-Arrays parsen k\u00f6nnen wir z. B. wie folgt:<\/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\">HexFormat hexFormat = HexFormat.ofDelimiter(<span class=\"hljs-string\">\" \"<\/span>).withPrefix(<span class=\"hljs-string\">\"0x\"<\/span>).withUpperCase();\n<span class=\"hljs-keyword\">byte<\/span>&#091;] bytes = hexFormat.parseHex(<span class=\"hljs-string\">\"0x01 0x02 0x03 0x3C 0x7E 0xFF\"<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Es gibt noch weitere Methoden, um z. B. nur einen Teilstring zu parsen. Eine vollst\u00e4ndige Dokumentation findest du im <a rel=\"noopener\" href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/util\/HexFormat.html\" target=\"_blank\">HexFormat-JavaDoc<\/a>.<\/p>\n\n\n\n<p><em>F\u00fcr diese Erweiterung gibt es kein JDK Enhancement Proposal.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"context-specific-deserialization-filters\">Context-Specific Deserialization Filters<\/h2>\n\n\n\n<p>Deserialisierung von Objekten stellt ein erhebliches Sicherheitsrisiko dar. B\u00f6swillige Angreifer k\u00f6nnen \u00fcber den zu deserialisierenden Datenstrom Objekte konstruieren, \u00fcber die sie letztendlich beliebigen Code in beliebigen (auf dem Classpath verf\u00fcgbaren) Klassen ausf\u00fchren k\u00f6nnen.<\/p>\n\n\n\n<p>In Java 9 wurden erstmals Deserialisierungsfilter eingef\u00fchrt, d. h. die M\u00f6glichkeit festzulegen, welche Klassen deserialisiert werden d\u00fcrfen (bzw. welche nicht).<\/p>\n\n\n\n<p>Bisher gab es zwei M\u00f6glichkeiten Deserialisierungsfilter zu definieren:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>per <code>ObjectInputStream.setObjectInputFilter()<\/code> f\u00fcr jede Deserialisierung separat,<\/li>\n\n\n\n<li>systemweit einheitlich per System Property <code>jdk.serialFilter<\/code> oder per gleichnamiger Security Property in der Datei <code>conf\/security\/java.properties<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>Bei komplexen Anwendungen, insbesondere bei solchen mit Drittanbieter-Bibliotheken, welche ebenfalls Deserialisierungs-Code enthalten, sind diese Varianten nicht zufriedenstellend. So kann bspw. die Deserialisierung in Drittanbieter-Code nicht per <code>ObjectInputStream.setObjectInputFilter()<\/code> konfiguriert werden (es sei denn, man \u00e4ndert deren Quellcode), sondern nur global.<\/p>\n\n\n\n<p><a href=\"https:\/\/openjdk.org:443\/jeps\/415\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 415<\/a> macht es ab Java 17 m\u00f6glich, Deserialisierungsfilter kontextspezifisch festzulegen, z. B. f\u00fcr einen bestimmten Thread oder basierend auf dem Call Stack f\u00fcr eine bestimmte Klasse, ein Modul, oder eine Drittanbieter-Bibliothek.<\/p>\n\n\n\n<p>Die Konfiguration der Filter ist nicht ganz einfach und w\u00fcrde den Rahmen dieses Artikels sprengen. Details findest du im oben verlinkten JEP.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"jdk-flight-recorder-event-for-deserialization\">JDK Flight Recorder Event for Deserialization<\/h3>\n\n\n\n<p>Ab Java 17 ist es au\u00dferdem m\u00f6glich die Deserialisierung von Objekten \u00fcber den JDK Flight Recorder (JFR) zu \u00fcberwachen.<\/p>\n\n\n\n<p>Deserialisierungsevents sind per Default deaktiviert und m\u00fcssen \u00fcber den Event-Bezeichner <code>jdk.Deserialization<\/code> in der JFR-Konfigurationsdatei aktiviert werden (ein Beispiel dazu findest du im unten verlinkten Artikel).<\/p>\n\n\n\n<p>Wenn ein Deserialisierungsfilter aktiviert ist, enth\u00e4lt das JFR-Event die Angabe dar\u00fcber, ob die Deserialisierung ausgef\u00fchrt oder abgewiesen wurde.<\/p>\n\n\n\n<p>Detailliertere Informationen und ein Beispiel findest du im Artikel \"<a rel=\"noopener\" href=\"https:\/\/inside.java\/2021\/03\/02\/monitoring-deserialization-activity-in-the-jdk\/\" target=\"_blank\">Monitoring Deserialization to Improve Application Security<\/a>\".<\/p>\n\n\n\n<p><em>Die Flight Recorder Events f\u00fcr die Deserialisierung sind nicht Teil des o. g. JDK Enhancement Proposals; auch existiert f\u00fcr sie kein separater JEP.<\/em><\/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=\"enhanced-pseudo-random-number-generators\">Enhanced Pseudo-Random Number Generators<\/h2>\n\n\n\n<p>Bisher war es aufw\u00e4ndig die <a href=\"\/de\/java\/zufallszahl\/\">Zufallszahlen-generierenden<\/a> Klassen <code>Random<\/code> und <code>SplittableRandom<\/code> in einer Anwendung auszutauschen (oder gar durch andere Algorithmen zu ersetzen) obwohl sie einen gr\u00f6\u00dftenteils \u00fcbereinstimmenden Satz von Methoden anbieten (z. B. <code>nextInt()<\/code>, <code>nextDouble()<\/code> und Stream-erzeugende Methoden wie <code>ints()<\/code> und <code>longs()<\/code>).<\/p>\n\n\n\n<p>Die Klassenhierarchie sah bisher so aus:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-half_600\"><img decoding=\"async\" width=\"600\" height=\"249\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-600x249.png\" alt=\"Pre-Java 17 Pseudo-Random Number Generators\" class=\"wp-image-25884\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-600x249.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-224x93.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-336x139.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-504x209.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-672x279.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-400x166.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-800x332.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17-944x392.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_pre_java17.png 1200w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><figcaption class=\"wp-element-caption\">Pre-Java 17 Pseudo-Random Number Generators<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Durch <a href=\"https:\/\/openjdk.org:443\/jeps\/356\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 356<\/a> wurde in Java 17 ein Framework von voneinander erbenden Interfaces f\u00fcr die bestehenden und f\u00fcr neue Algorithmen eingef\u00fchrt, so dass die konkreten Algorithmen in Zukunft einfach austauschbar sind:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"438\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-800x438.png\" alt=\"Java 17 Pseudo-Random Number Generators\" class=\"wp-image-25888\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-800x438.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-224x123.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-336x184.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-504x276.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-672x368.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-400x219.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-600x328.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-944x516.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17-1200x656.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/random_number_generators_java17.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">Java 17 Pseudo-Random Number Generators<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Die allen Zufallszahlengeneratoren gemeinsamen Methoden wie <code>nextInt()<\/code> und <code>nextDouble()<\/code> sind in <code>RandomGenerator<\/code> definiert. Sofern du nur diese Methoden ben\u00f6tigst, solltest du also in Zukunft immer dieses Interface verwenden.<\/p>\n\n\n\n<p>Das Framework enth\u00e4lt drei neue Typen von Zufallszahlengeneratoren:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>JumpableGenerator<\/code>: bietet Methoden, um eine gro\u00dfe Anzahl Zufallszahlen (z. B. 2<sup>64<\/sup>) zu \u00fcberspringen.<\/li>\n\n\n\n<li><code>LeapableGenerator<\/code>: bietet Methoden, um eine <em>sehr<\/em> gro\u00dfe Anzahl Zufallszahlen (z. B. 2<sup>128<\/sup>) zu \u00fcberspringen.<\/li>\n\n\n\n<li><code>ArbitrarilyJumpableGenerator<\/code>: bietet zus\u00e4tzliche Methoden, um eine <em>beliebige<\/em> Anzahl Zufallszahlen zu \u00fcberspringen.<\/li>\n<\/ul>\n\n\n\n<p>Au\u00dferdem wurde in den existierenden Klassen duplizierter Code eliminiert und Code in nicht \u00f6ffentliche abstrakte Klassen (nicht sichtbar im Klassendiagramm) extrahiert, um ihn f\u00fcr zuk\u00fcnftige Implementierungen von Zufallszahlengeneratoren wiederverwendbar zu machen.<\/p>\n\n\n\n<p>Neue Zufallszahlengeneratoren k\u00f6nnen in Zukunft \u00fcber das Service Provider Interface (SPI) hinzugef\u00fcgt und \u00fcber <code>RandomGeneratorFactory<\/code> instanziiert werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"performance\">Performance<\/h2>\n\n\n\n<p>Java 17 bringt mit asynchronem Logging eine l\u00e4ngst \u00fcberf\u00e4llige Performance-Verbesserung des in Java 9 eingef\u00fchrten Unified JVM Logging Systems.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"unified-logging-supports-asynchronous-log-flushing\">Unified Logging Supports Asynchronous Log Flushing<\/h3>\n\n\n\n<p>Asynchrones Logging ist ein Feature, das alle Java-Logging-Frameworks unterst\u00fctzen. Dabei werden Log-Nachrichten durch den Anwendungsthread zun\u00e4chst in eine Queue geschrieben. Ein separater I\/O-Thread leitet sie dann an den konfigurierten Ausgang (Konsole, Datei oder Netzwerk) weiter.<\/p>\n\n\n\n<p>Der Anwendungs-Thread muss so nicht darauf warten, dass das I\/O-Subsytem die Nachricht verarbeitet hat.<\/p>\n\n\n\n<p>Ab Java 17 kann auch f\u00fcr die JVM selbst asynchrones Logging aktiviert werden. Dies geschieht \u00fcber folgende VM-Option:<\/p>\n\n\n\n<p class=\"has-text-align-center\"><code>-Xlog:async<\/code><\/p>\n\n\n\n<p>Die Logging-Queue ist auf eine festgelegte Gr\u00f6\u00dfe beschr\u00e4nkt. Wenn die Anwendung mehr Log-Nachrichten sendet als der I\/O-Thread abarbeiten kann, l\u00e4uft die Queue voll. Weitere Nachrichten verwirft sie dann kommentarlos.<\/p>\n\n\n\n<p>Die Gr\u00f6\u00dfe der Queue kann \u00fcber folgende VM-Option angepasst werden:<\/p>\n\n\n\n<p class=\"has-text-align-center\"><code>-XX:AsyncLogBufferSize=&lt;Bytes&gt;<\/code><\/p>\n\n\n\n<p> <em>F\u00fcr diese Erweiterung gibt es kein JDK Enhancement Proposal.<\/em> <\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"preview-und-incubator-features\">Preview- und Incubator-Features<\/h2>\n\n\n\n<p>Auch wenn Java 17 ein Long-Term-Support (LTS) Release darstellt, enth\u00e4lt es Preview- und Incubator-Features, die voraussichtlich in einem der n\u00e4chsten \"Zwischen-Releases\" Produktionsreife erlangen werden. Wer nur LTS-Releases einsetzt, muss also mindestens bis Java 23 warten, um diese Features einzusetzen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"pattern-matching-for-switch-preview\">Pattern Matching for switch (Preview)<\/h3>\n\n\n\n<p>In Java 16 wurde <a href=\"\/de\/java\/java-16-features\/#Pattern_Matching_for_instanceof\">\"Pattern Matching for instanceof\"<\/a> eingef\u00fchrt. Damit wurden explizite Casts nach <code>instanceof<\/code>-Pr\u00fcfungen \u00fcberfl\u00fcssig. Das erm\u00f6glicht z. B. Code wie den folgenden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s) {\n  <span class=\"hljs-keyword\">if<\/span> (s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n    System.out.println(s.toUpperCase());\n  } <span class=\"hljs-keyword\">else<\/span> {\n    System.out.println(s.toLowerCase());\n  }\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer i) {\n  System.out.println(i * i);\n}<\/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>Durch <a href=\"https:\/\/openjdk.org:443\/jeps\/406\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 406<\/a> l\u00e4sst sich die Pr\u00fcfung, ob ein Objekt eine Instanz einer bestimmten Klasse ist, in Zukunft auch als <code>switch<\/code>-Statement (oder -Ausdruck) schreiben.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"pattern-matching-fur-switch-statements\">Pattern Matching f\u00fcr switch-Statements<\/h4>\n\n\n\n<p>Hier das Beispiel von oben umgeschrieben in ein <code>switch<\/code>-Statement:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">switch<\/span> (obj) {\n  <span class=\"hljs-keyword\">case<\/span> String s -&gt; {\n    <span class=\"hljs-keyword\">if<\/span> (s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n      System.out.println(s.toUpperCase());\n    } <span class=\"hljs-keyword\">else<\/span> {\n      System.out.println(s.toLowerCase());\n    }\n  }\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-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>Auff\u00e4llig ist, dass der <code>default<\/code>-Fall angegeben werden muss \u2013 in diesem Fall mit einem leeren Codeblock, da nur f\u00fcr Strings und Integers eine Aktion ausgef\u00fchrt werden soll.<\/p>\n\n\n\n<p>Deutlich lesbarer wird der Code, wenn wir <code>case<\/code>- und <code>if<\/code>-Ausdr\u00fccke per logischem \"und\" kombinieren (das nennt sich dann \"guarded pattern\"):<\/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 shcb-code-table shcb-line-numbers\"><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 &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> String s                   -&gt; System.out.println(s.toLowerCase());\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">case<\/span> Integer i                  -&gt; System.out.println(i * i);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">default<\/span> -&gt; {}\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/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>Wichtig dabei ist, dass ein sogenanntes \"dominier<em>endes<\/em> Pattern\" nach einem \"dominier<em>ten<\/em> Pattern\" stehen muss. Im Beispiel dominiert das k\u00fcrzere Pattern aus Zeile 3 \"String s\" das l\u00e4ngere aus Zeile 2.<\/p>\n\n\n\n<p>Wenn wir diese Zeilen vertauschen w\u00fcrden, s\u00e4he das so aus:<\/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 shcb-code-table shcb-line-numbers\"><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><span class='shcb-loc'><span>}\n<\/span><\/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>Der Compiler w\u00fcrde in diesem Fall Zeile 3 mit folgender Fehlermeldung bem\u00e4ngeln:<\/p>\n\n\n\n<p class=\"has-text-align-center\"><em>Label is dominated by a preceding case label 'String s'<\/em><\/p>\n\n\n\n<p>Der Grund daf\u00fcr ist, dass nun jeder String \u2013 egal welcher L\u00e4nge \u2013 durch das Pattern \"String s\" (Zeile 2) gematcht wird und gar nicht erst bis zur zweiten Fallpr\u00fcfung (Zeile 3) kommt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"pattern-matching-fur-switch-expressions\">Pattern Matching f\u00fcr switch Expressions<\/h4>\n\n\n\n<p>Pattern Matching kann auch f\u00fcr <a href=\"\/de\/java\/switch-expressions\/#switch-als-ausdruck-mit-ruckgabewert\"><code>switch<\/code>-Ausdr\u00fccke<\/a> (also <code>switch<\/code> mit R\u00fcckgabewert) eingesetzt werden:<\/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\">String output = <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; s.toUpperCase();\n  <span class=\"hljs-keyword\">case<\/span> String s                   -&gt; s.toLowerCase();\n\n  <span class=\"hljs-keyword\">case<\/span> Integer i                  -&gt; String.valueOf(i * i);\n  \n  <span class=\"hljs-keyword\">default<\/span> -&gt; <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> IllegalStateException(<span class=\"hljs-string\">\"Unexpected value: \"<\/span> + obj);\n};\n<\/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>Hierbei muss der <code>default<\/code>-Fall einen Wert zur\u00fcckgeben, da sonst der R\u00fcckgabewert des <code>switch<\/code>-Ausdrucks undefiniert sein k\u00f6nnte \u2013 oder, wie im Beispiel, eine Exception werfen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"vollstandigkeitsprufung-mit-sealed-classes\">Vollst\u00e4ndigkeitspr\u00fcfung mit Sealed Classes<\/h4>\n\n\n\n<p>Bei der Verwendung von <a href=\"\/de\/java\/sealed-classes\/\">Sealed Classes<\/a> kann der Compiler \u00fcbrigens pr\u00fcfen, ob <code>switch<\/code>-Statement bzw. -Ausdruck vollst\u00e4ndig sind. Wenn das der Fall ist, wird ein <code>default<\/code>-Fall nicht ben\u00f6tigt.<\/p>\n\n\n\n<p>Das hat noch einen nicht sofort ersichtlichen Vorteil: Wird eines Tages die versiegelte Hierarchie erweitert, erkennt der Compilier den dann unvollst\u00e4ndigen <code>switch<\/code>-Ausdruck, und man wird gezwungen sein, diesen zu vervollst\u00e4ndigen. Das erspart einem unbemerkte Fehler.<\/p>\n\n\n\n<p>\"Pattern Matching for switch\" wird in <a href=\"\/de\/java\/java-18-features\/#Pattern_Matching_for_switch_Second_Preview\">Java 18<\/a> noch einmal als Preview-Feature vorgelegt werden und vorraussichtlich in Java 19 Produktionsreife erlangen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"foreign-function-memory-api-incubator\">Foreign Function &amp; Memory API (Incubator)<\/h3>\n\n\n\n<p>Seit Java 1.1 bietet das Java Native Interface (JNI) die M\u00f6glichkeit von Java heraus nativen C-Code aufzurufen. JNI ist jedoch \u00e4u\u00dfert aufw\u00e4ndig in der Implementierung und langsam in der Ausf\u00fchrung.<\/p>\n\n\n\n<p>Um einen JNI-Ersatz zu schaffen, wurde <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/panama\/\" target=\"_blank\">Project Panama<\/a> ins Leben gerufen. Konkrete Ziele dieses Projekts sind a) den Aufwand der Implementierung zu vereinfachen (90 % der Arbeit soll eliminiert werden) und b) die Verbesserung der Leistung (um Faktor 4 bis 5).<\/p>\n\n\n\n<p>In den vergangenen drei Java-Versionen wurden zwei neue APIs jeweils im Inkubator-Stadium vorgestellt:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Die Foreign Memory Access API (eingef\u00fchrt in <a href=\"\/de\/java\/java-14-features\/#Foreign-Memory_Access_API_Incubator\">Java 14<\/a>, verfeinert in <a href=\"\/de\/java\/java-15-features\/#Foreign-Memory_Access_API_Second_Incubator\">Java 15<\/a> und <a href=\"\/de\/java\/java-16-features\/#Foreign_Linker_API_Incubator_Foreign-Memory_Access_API_Third_Incubator\">Java 16<\/a>),<\/li>\n\n\n\n<li>Die Foreign Linker API (eingef\u00fchrt in <a href=\"\/de\/java\/java-16-features\/#Foreign_Linker_API_Incubator_Foreign-Memory_Access_API_Third_Incubator\">Java 16<\/a>).<\/li>\n<\/ol>\n\n\n\n<p>Durch <a href=\"https:\/\/openjdk.org:443\/jeps\/412\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 412<\/a> wurden beide APIs in Java 17 zur \"Foreign Function &amp; Memory API\" zusammengefasst.<\/p>\n\n\n\n<p>Diese befindet sich nach wie vor im Inkubator-Stadium, kann also noch wesentlichen \u00c4nderungen unterliegen. Ich werde die neue API im Artikel \u00fcber <a href=\"\/de\/java\/java-19-features\/#Foreign_Function_Memory_API_Preview\">Java 19<\/a> vorstellen, wenn sie das Preview-Stadium erreicht hat.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vector-api-second-incubator\">Vector API (Second Incubator)<\/h3>\n\n\n\n<p>Bei der Vector-API geht es \u2013 wie im <a href=\"\/de\/java\/java-16-features\/#Vector_API_Incubator\">Artikel \u00fcber Java 16<\/a> bereits beschrieben \u2013 nicht um die alte <code>java.util.Vector<\/code>-Klasse, sondern um die Abbildung mathematischer Vektorrechnungen auf moderne CPU-Architekturen mit Single-Instruction-Multiple-Data-(SIMD)-Support.<\/p>\n\n\n\n<p>Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/414\" target=\"_blank\">JDK Enhancement Proposal 414<\/a> wurde die Leistung verbessert und die API erweitert, z. B. um Unterst\u00fctzung von <code>Character<\/code> (bisher wurden <code>Byte<\/code>, <code>Short<\/code>, <code>Integer<\/code>, <code>Long<\/code>, <code>Float<\/code> und <code>Double<\/code> unterst\u00fctzt).<\/p>\n\n\n\n<p>Da Features im Incubator-Status noch wesentlichen \u00c4nderungen erfahren k\u00f6nnen, werde ich das Feature dann vorstellen, wenn es den Preview-Status erreicht.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecations-und-loeschungen\">Deprecations und L\u00f6schungen<\/h2>\n\n\n\n<p>In Java 17 wurden wieder einige veraltete Features als \"deprecated for removal\" markiert bzw. vollst\u00e4ndig entfernt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecate-the-applet-api-for-removal\">Deprecate the Applet API for Removal<\/h3>\n\n\n\n<p>Java Applets werden von keinem modernen Webbrowser mehr unterst\u00fctzt und wurden bereits in Java 9 als \"deprecated\" markiert.<\/p>\n\n\n\n<p>Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/398\" target=\"_blank\">JDK Enhancement Proposal 398<\/a> werden sie in Java 17 als \"deprecated for removal\" markiert. Das bedeutet, dass sie in einem der n\u00e4chsten Releases vollkommen entfernt werden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecate-the-security-manager-for-removal\">Deprecate the Security Manager for Removal<\/h3>\n\n\n\n<p>Der Security Manager ist seit Java 1.0 Bestandteil der Plattform und sollte in erster Linie den Rechner und die Daten der User vor heruntergeladenen Java-Applets sch\u00fctzen. Diese wurden in einer Sandbox gestartet, in der der Security Manager den Zugriff auf Ressourcen wie das Dateisystem oder das Netzwerk grunds\u00e4tzlich verwehrte.<\/p>\n\n\n\n<p>Wie im vorangegangenen Abschnitt beschrieben, wurden Java Applets als \u201cdeprecated for removal\u201d gekennzeichnet; dieser Aspekt des Security Managers wird also nicht l\u00e4nger von Bedeutung sein.<\/p>\n\n\n\n<p>Neben der Browser-Sandbox, die den Zugriff auf Ressourcen <em>generell<\/em> verwehrte, konnte der Security Manager \u00fcber Policy Files auch Server-Anwendungen absichern. Beispiele daf\u00fcr sind Elasticsearch und Tomcat.<\/p>\n\n\n\n<p>Allerdings besteht daran kein allzu gro\u00dfes Interesse mehr, da die Konfiguration kompliziert ist und sich Sicherheit \u00fcber das Java-Modulsystem oder Isolierung durch Containerisierung heutzutage besser realisieren l\u00e4sst.<\/p>\n\n\n\n<p>Dar\u00fcber hinaus stellt der Security Manager einen nicht unerheblichen Wartungsaufwand dar. F\u00fcr alle Erweiterungen an der Java-Klassenbibliothek muss evaluiert werden, inwieweit diese \u00fcber den Security Manager abgesichert werden m\u00fcssen.<\/p>\n\n\n\n<p>Aus diesen Gr\u00fcnden wurde der Security Manager durch <a href=\"https:\/\/openjdk.org:443\/jeps\/411\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 411<\/a> in Java 17 als \"deprecated for removal\" eingestuft.<\/p>\n\n\n\n<p>Ab <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#Permanently_Disable_the_Security_Manager_JEP_486\">Java 24<\/a> wird der Security Manager nicht mehr aktivierbar sein. Wann der Security Manager vollst\u00e4ndig entfernt werden wird, steht noch nicht fest.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"remove-rmi-activation\">Remove RMI Activation<\/h3>\n\n\n\n<p>Remote Method Invocation ist eine Technologie zum Aufruf von Methoden auf \"entfernten Objekten\", also Objekten auf einer anderen JVM.<\/p>\n\n\n\n<p>Durch RMI Activation k\u00f6nnen Objekte, die auf der Ziel-JVM zerst\u00f6rt wurden, automatisch wieder instanziiert werden, sobald auf sie zugegriffen wird. Dies soll eine Fehlerbehandlung auf der Client-Seite \u00fcberfl\u00fcssig machen.<\/p>\n\n\n\n<p>RMI Activation ist jedoch relativ komplex und f\u00fchrt zu laufenden Wartungskosten; zudem ist es praktisch ungenutzt, wie Analysen von Open-Source-Projekten und Foren wie StackOverflow gezeigt haben.<\/p>\n\n\n\n<p>Aus diesem Grund wurde RMI Activation in <a href=\"\/de\/java\/java-15-features\/#Deprecate_RMI_Activation_for_Removal\">Java 15<\/a> als \"veraltet\" markiert und in Java 17 durch <a href=\"https:\/\/openjdk.org:443\/jeps\/407\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 407<\/a> vollst\u00e4ndig entfernt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"remove-the-experimental-aot-and-jit-compiler\">Remove the Experimental AOT and JIT Compiler<\/h3>\n\n\n\n<p>In Java 9 wurde Graal als experimenteller Ahead-of-Time (AOT) Compiler dem JDK hinzugef\u00fcgt. In <a href=\"\/de\/java\/java-10-features\/#Experimental_Java-Based_JIT_Compiler\">Java 10<\/a> wurde Graal dann auch als Just-in-Time (JIT) Compiler verf\u00fcgbar gemacht.<\/p>\n\n\n\n<p>Allerdings wurde beide Features seither wenig genutzt. Da der Wartungsaufwand erheblich ist, wurde Graal in den von Oracle ver\u00f6ffentlichten JDK 16-Builds entfernt. Da sich niemand dar\u00fcber beschwert hat, wurden sowohl AOT- als auch JIT-Compiler in Java 17 mit <a href=\"https:\/\/openjdk.org:443\/jeps\/410\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 410<\/a> vollst\u00e4ndig entfernt.<\/p>\n\n\n\n<p>Das zur Anbindung von Graal genutzte Java-Level JVM-Compiler-Interface (JVMCI) wurde nicht entfernt, und Graal selbst wird auch weiterentwickelt. Um Graal als AOT- oder JIT-Compiler zu verwenden, kannst du die Java-Distribution <a rel=\"noopener\" href=\"https:\/\/www.graalvm.org\/\" target=\"_blank\">GraalVM<\/a> herunterladen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-17\">Sonstige \u00c4nderungen in Java 17<\/h2>\n\n\n\n<p>In diesem Abschnitt findest du kleinere \u00c4nderungen der Java-Klassenbibliothek, mit denen du nicht t\u00e4glich in Kontakt kommen wirst. Dennoch empfehle ich dir sie zumindest einmal zu \u00fcberfliegen, so dass du wei\u00dft, wo du nachschauen musst, wenn du eine entsprechende Funktion ben\u00f6tigst.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"new-api-for-accessing-large-icons\">New API for Accessing Large Icons<\/h3>\n\n\n\n<p>Hier ist eine kleine Swing-Anwendung, die unter Windows das Dateisystem-Icon des Verzeichnisses <code>C:\\Windows<\/code> darstellt:<\/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\">FileSystemView fileSystemView = FileSystemView.getFileSystemView();\nIcon icon = fileSystemView.getSystemIcon(<span class=\"hljs-keyword\">new<\/span> File(<span class=\"hljs-string\">\"C:\\\\Windows\"<\/span>));\n\nJFrame frame = <span class=\"hljs-keyword\">new<\/span> JFrame();\nframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\nframe.getContentPane().add(<span class=\"hljs-keyword\">new<\/span> JLabel(icon));\nframe.pack();\nframe.setVisible(<span class=\"hljs-keyword\">true<\/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>Das Icon hat eine Gr\u00f6\u00dfe von 16 x 16 Pixeln, und es gab bisher keine M\u00f6glichkeit ein hochaufl\u00f6senderes Icon anzuzeigen. <\/p>\n\n\n\n<p>In Java 17 kam die Methode <code>getSystemIcon(File f, int width, int height)<\/code> hinzu, mit der du die Gr\u00f6\u00dfe des Icons angeben kannst:<\/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\">Icon icon = fileSystemView.getSystemIcon(<span class=\"hljs-keyword\">new<\/span> File(<span class=\"hljs-string\">\"C:\\\\Windows\"<\/span>), <span class=\"hljs-number\">512<\/span>, <span class=\"hljs-number\">512<\/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><em>F\u00fcr diese Erweiterung gibt es kein JDK Enhancement Proposal.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"add-support-for-userdefinedfileattributeview-on-macos\">Add support for UserDefinedFileAttributeView on macOS<\/h3>\n\n\n\n<p>Der folgende Code zeigt, wie erweiterte Attribute einer Datei geschrieben und gelesen werden k\u00f6nnen:<\/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\">Path path = ...\n\nUserDefinedFileAttributeView view =\n    Files.getFileAttributeView(path, UserDefinedFileAttributeView<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>)<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Write the extended attribute with name \"foo\" and value \"bar\"<\/span>\nview.write(<span class=\"hljs-string\">\"foo\"<\/span>, StandardCharsets.UTF_8.encode(<span class=\"hljs-string\">\"bar\"<\/span>));\n\n<span class=\"hljs-comment\">\/\/ Print a list of all extended attribute names<\/span>\nSystem.out.println(<span class=\"hljs-string\">\"attribute names: \"<\/span> + view.list());\n\n<span class=\"hljs-comment\">\/\/ Read the extended attribute \"foo\"<\/span>\nByteBuffer byteBuffer = ByteBuffer.allocate(<span class=\"hljs-number\">1024<\/span>);\nview.read(<span class=\"hljs-string\">\"foo\"<\/span>, byteBuffer);\nbyteBuffer.flip();\nString value = StandardCharsets.UTF_8.decode(byteBuffer).toString();\nSystem.out.println(<span class=\"hljs-string\">\"value of 'foo': \"<\/span> + value);<\/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>Diese Funktionalit\u00e4t existiert seit Java 7, wurde jedoch auch macOS bisher nicht unterst\u00fctzt. Seit Java 17 ist die Funktion nun auch f\u00fcr macOS verf\u00fcgbar.<\/p>\n\n\n\n<p><em>F\u00fcr diese Erweiterung gibt es kein JDK Enhancement Proposal.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"system-property-for-native-character-encoding-name\">System Property for Native Character Encoding Name<\/h3>\n\n\n\n<p>\u00dcber die System Property \"native.encoding\" kann ab Java 17 die Standard-Zeichenkodierung des Betriebssystems abgerufen werden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">System.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-31\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Unter Windows wird <code>Cp1252<\/code> ausgegeben, unter Linux und macOS <code>UTF-8<\/code>.<\/p>\n\n\n\n<p>Rufst du diesen Code mit Java 16 oder fr\u00fcher auf, wird <code>null<\/code> ausgegeben.<\/p>\n\n\n\n<p><em>F\u00fcr diese Erweiterung gibt es kein JDK Enhancement Proposal.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"restore-always-strict-floating-point-semantics\">Restore Always-Strict Floating-Point Semantics<\/h3>\n\n\n\n<p>Ein nahezu unbekanntes Java-Keyword ist <code>strictfp<\/code>. Es wird in Klassendefinitionen verwendet, um Flie\u00dfkommaoperationen innerhalb einer Klasse \"strict\" zu machen. Das bedeutet, dass sie auf allen Architekturen zu den gleichen, vorhersagbaren Resultaten f\u00fchren.<\/p>\n\n\n\n<p>Strikte Flie\u00dfkomma-Semantik war das Standardverhalten vor Java 1.2 (also vor mehr als 20 Jahren).<\/p>\n\n\n\n<p>Ab Java 1.2 wurde standarm\u00e4\u00dfig die \"Standard-Flie\u00dfkomma-Semantik\" verwendet, die je nach Prozessor-Architektur zu leicht abweichenden Ergebnissen f\u00fchren konnte. Daf\u00fcr war sie insbesondere auf dem damals verbreiteten x87-Gleitkomma-Koprozessor performanter, da dieser f\u00fcr die strikte Semantik zus\u00e4tzliche Operationen ausf\u00fchren musste (weitere Details findest du in diesem <a rel=\"noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Strictfp\" target=\"_blank\">Wikipedia-Artikel<\/a>).<\/p>\n\n\n\n<p>Wer ab Java 1.2 weiterhin strikt rechnen wollte, musste dies durch das Keyword <code>strictfp<\/code> in der Klassendefinition kennzeichnen:<\/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-keyword\">strictfp<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">PredictiveCalculator<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Moderne Hardware kann die strikte Flie\u00dfkomma-Semantik ohne Performance-Einbu\u00dfen durchf\u00fchren, so dass im <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/306\" target=\"_blank\">JDK Enhancement Proposal 306<\/a> entschieden wurde, diese ab Java 17 wieder zur Standard-Semantik zu machen.<\/p>\n\n\n\n<p>Das <code>strictfp<\/code>-Keyword ist damit \u00fcberfl\u00fcssig. Die Verwendung f\u00fchrt zu einer Compiler-Warnung:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ javac PredictiveCalculator.java\nPredictiveCalculator.java:3: warning: &#091;strictfp] as of release 17, \nall floating-point expressions are evaluated strictly and 'strictfp' is not required\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"new-macos-rendering-pipeline\">New macOS Rendering Pipeline<\/h3>\n\n\n\n<p>Apple hat 2018 die bisher von Java Swing f\u00fcr das Rendering unter macOS eingesetzte OpenGL-Bibliothek als \"deprecated\" markiert und das <a href=\"https:\/\/developer.apple.com\/metal\/\" target=\"_blank\" rel=\"noopener\">Metal-Framework<\/a> als deren Nachfolger vorgestellt.<\/p>\n\n\n\n<p>Durch <a href=\"https:\/\/openjdk.org:443\/jeps\/382\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 382<\/a> wird die Swing-Rendering-Pipeline f\u00fcr macOS auf die Metal API umgestellt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"macos-aarch64-port\">macOS\/AArch64 Port<\/h3>\n\n\n\n<p>Apple hat angek\u00fcndigt, Macs langfristig von x64- auf AArch64-CPUs umzustellen. Dementsprechend wird mit <a href=\"https:\/\/openjdk.org:443\/jeps\/391\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 391<\/a> ein entsprechender Port bereitgestellt.<\/p>\n\n\n\n<p>Der Code ist eine Erweiterung der in Java 9 und <a href=\"\/de\/java\/java-16-features\/#WindowsAArch64_Port\">Java 16<\/a> ver\u00f6ffentlichten AArch64-Ports f\u00fcr Linux und Windows um macOS-spezifische Anpassungen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"new-page-for-new-api-and-improved-deprecated-page\">New Page for \"New API\" and Improved \"Deprecated\" Page<\/h3>\n\n\n\n<p>In ab Java 17 generiertem JavaDoc gibt es eine Seite \"NEW\", die alle neuen Features, gruppiert nach Version anzeigt. Dazu werden die <code>@since<\/code>-Tags der Module, Pakete, Klassen, etc. ausgewertet.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"503\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-800x503.png\" alt=\"&quot;NEW&quot;-Seite in seit Java 17 generiertem JavaDoc\" class=\"wp-image-25863\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-800x503.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-224x141.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-336x211.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-504x317.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-672x423.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-400x252.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-600x377.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-944x594.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17-1200x755.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_since_java_17.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">\"NEW\"-Seite in seit Java 17 generiertem JavaDoc<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Au\u00dferdem wurde die \"DEPRECATED\"-Seite \u00fcberarbeitet. Bis Java 16 sehen wir hier eine ungruppierte Liste aller als \"deprecated\" markierten Features:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"435\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-800x435.png\" alt=\"&quot;DEPRECATED&quot;-Seite von Java 16\" class=\"wp-image-25864\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-800x435.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-224x122.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-336x183.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-504x274.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-672x365.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-400x218.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-600x326.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-944x513.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16-1200x653.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_16.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">\"DEPRECATED\"-Seite von Java 16<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Ab Java 17 sehen wir die als \"deprecated\" markierten Features gruppiert nach Release:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"460\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-800x460.png\" alt=\" &quot;DEPRECATED&quot;-Seite von Java 17 \" class=\"wp-image-25865\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-800x460.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-224x129.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-336x193.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-504x290.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-672x386.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-400x230.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-600x345.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-944x543.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17-1200x690.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/javadoc_deprecated_java_17.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\"> \"DEPRECATED\"-Seite von Java 17 <\/figcaption><\/figure>\n<\/div>\n\n\n<p><em>F\u00fcr diese Erweiterung gibt es kein 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-17\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 17<\/h3>\n\n\n\n<p>Dieser Artikel hat alle \u00c4nderungen pr\u00e4sentiert, die in JDK Enhancement Proposals (JEPs) definiert sind sowie zahlreiche Erweiterungen der Klassenbibliothek, f\u00fcr die keine JEPs existieren. Weitere \u00c4nderungen, insbesondere an den Sicherheitsbibliotheken, findest du in den <a rel=\"noopener\" href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/17-relnote-issues.html\" target=\"_blank\">offiziellen Java 17 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>Auch wenn Java 17 das neueste LTS-Release darstellt, unterscheidet sich dieses Release nicht wesentlich von den vorherigen. Wir haben wieder eine Mischung bekommen aus:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>neuen Sprach-Features (Sealed Classes),<\/li>\n\n\n\n<li>API-\u00c4nderungen (<code>InstantSource<\/code>, <code>HexFormat<\/code>, kontextspezifische Deserialisierungsfilter), <\/li>\n\n\n\n<li>einer Performance-Verbesserung (asynchrones Logging der JVM),<\/li>\n\n\n\n<li>Deprecations und L\u00f6schungen (Applet API, Security Manager, RMI Activation, AOT und JIT Compiler)<\/li>\n\n\n\n<li>und neuen Preview- und Incubator-Features (Pattern Matching for switch, Foreign Function &amp; Memory API, Vector API).<\/li>\n<\/ul>\n\n\n\n<p>Au\u00dferdem wurde der in Java 9 mit Project Jigsaw eingeschlagene Weg zum Ende gebracht, indem der \u00fcbergangsweise bereitgestellte \"Relaxed Strong Encapsulation\"-Modus entfernt wurde und Zugriff auf private Members anderer Module (Deep Reflection) immer explizit freigegeben werden muss.<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neue Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>Alle neuen Features von Java 17 mit Beispielen: Sealed Classes, InstantSource, HexFormat, kontextspezifische Deserialisierungsfilter und mehr...<\/p>\n","protected":false},"author":1,"featured_media":34262,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"none","_seopress_titles_title":"","_seopress_titles_desc":"Die neuen Features von Java 17 (LTS) mit Beispielen: Sealed Classes, InstantSource, HexFormat, kontextspezifische Deserialisierungsfilter und mehr.","_seopress_robots_index":"","_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":35259,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-25819","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\/2021\/12\/java-17-features.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-features.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-17-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 17 mit Beispielen: Sealed Classes, InstantSource, HexFormat, kontextspezifische Deserialisierungsfilter und mehr...","public_identification_id":"31dd7b3a88ed4725a7084faa57cd68d0","private_identification_id":"b43dbb4cbc2e4caeac095a529ede6a78","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/25819","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=25819"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/25819\/revisions"}],"predecessor-version":[{"id":52381,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/25819\/revisions\/52381"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34262"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=25819"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=25819"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=25819"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}