{"id":25448,"date":"2021-12-07T17:00:00","date_gmt":"2021-12-07T16:00:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=25448"},"modified":"2026-04-15T14:52:47","modified_gmt":"2026-04-15T12:52:47","slug":"java-16-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-16-features\/","title":{"rendered":"Java 16 Features (mit Beispielen)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Mit dem am 16. M\u00e4rz 2021 ver\u00f6ffentlichten Java 16 erreichen zwei neue Sprach-Features aus Project Amber die Produktionsreife: \"Pattern Matching for instanceof\" und Records.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Insgesamt wurden f\u00fcr dieses Release beeindruckende 17 JDK Enhancement Proposals umgesetzt. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ich habe wie immer versucht die Erweiterungen nach Relevanz f\u00fcr die t\u00e4gliche Programmierarbeit zu sortieren. D. h. du findest am Anfang des Artikels die bereits erw\u00e4hnten neuen Sprach-Features, wichtige \u00c4nderungen an der JDK-Klassenbibliothek und neue Tools. Danach folgen Performance-Verbesserungen, Preview- und Incubator-Features und zuletzt sonstige \u00c4nderungen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wie immer verwende ich die englischen Bezeichnungen der JEPs, da eine \u00dcbersetzung ins Deutsche hier eher verwirrt als dass sie einen Mehrwert bringt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"pattern-matching-for-instanceof\">Pattern Matching for instanceof<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kommen wir zur ersten gro\u00dfen Neuerung in Java 16. Nach zwei Preview-Runden wurde \"Pattern Matching for instanceof\" durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/394\" target=\"_blank\">JDK Enhancement Proposal 394<\/a> als produktionsreif ver\u00f6ffentlicht.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Diese nunmehr vierte Spracherweiterung aus <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/amber\/\" target=\"_blank\">Project Amber<\/a> eliminiert die Notwendingkeit von Casts nach einer <code>instanceof<\/code>-Pr\u00fcfung durch eine implizite Typumwandlung.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Was das bedeutet, erkl\u00e4re ich am besten an einem Beispiel. Der folgende Code pr\u00fcft die Klasse eines Objekts. Ist das Objekt ein String, der au\u00dferdem l\u00e4nger als f\u00fcnf Zeichen ist, wird er in Gro\u00dfbuchstaben umgewandelt und ausgegeben. Ist das Objekt hingegen ein Integer, wird die Zahl quadriert und ausgegeben.<\/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 shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>Object obj = getObject();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String) {\n<\/span><\/span><span class='shcb-loc'><span>  String s = (String) obj;\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n<\/span><\/span><span class='shcb-loc'><span>    System.out.println(s.toUpperCase());\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer) {\n<\/span><\/span><span class='shcb-loc'><span>  Integer i = (Integer) obj;\n<\/span><\/span><span class='shcb-loc'><span>  System.out.println(i * i);\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In den Zeilen 4 und 9 m\u00fcssen wir das Objekt nach <code>String<\/code> bzw. <code>Integer<\/code> casten. Wie haben uns so an diese Schreibweise gew\u00f6hnt, dass wir den notwendigen Boilerplate-Code gar nicht mehr in Frage stellen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wie es seit Java 16 besser geht, zeigt der folgende Code: <\/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 shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s) {          <span class=\"hljs-comment\">\/\/ &lt;-- implicit cast to String s<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n<\/span><\/span><span class='shcb-loc'><span>    System.out.println(s.toUpperCase());\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer i) {  <span class=\"hljs-comment\">\/\/ &lt;-- implicit cast to Integer i<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  System.out.println(i * i);\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Anstatt explizite Casts zu programmieren, m\u00fcssen wir lediglich einen Variablennamen hinter die <code>instanceof<\/code>-Pr\u00fcfung setzen (Zeilen 1 und 5). Diese Variable ist dann vom in <code>instanceof<\/code> gepr\u00fcften Zieltyp und innerhalb des <code>if<\/code>-Blocks sichtbar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wir k\u00f6nnen noch einen Schritt weitergehen und die ersten beiden <code>if<\/code>-Statements kombinieren:<\/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 shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s &amp;&amp; s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n<\/span><\/span><span class='shcb-loc'><span>  System.out.println(s.toUpperCase());\n<\/span><\/span><span class='shcb-loc'><span>} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer i) {\n<\/span><\/span><span class='shcb-loc'><span>  System.out.println(i * i);\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Der Code ist mit f\u00fcnf statt neun Zeilen nun deutlich pr\u00e4gnanter. Durch Pattern Matching wurde Redundanz eliminiert und die Lesbarkeit erh\u00f6ht.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Pattern Matching for instanceof \u2013 Scope<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Eine gematchte Variable ist nur innerhalb des <code>if<\/code>-Blocks bekannt. Das ist logisch, denn nur wenn der <code>if<\/code>-Vergleich positiv ausf\u00fcllt, kann die Variable auf den gew\u00fcnschten Typ gecastet werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn ein Feld mit gleichem Namen innerhalb der Klasse existiert, dann wird dieses Feld durch eine Pattern-Matching-Variable \"geshadowed\". Was das bedeutet, zeigt folgendes Beispiel:<\/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 shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">PatternMatchingScopeTest<\/span> <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">new<\/span> PatternMatchingScopeTest().processObject(<span class=\"hljs-string\">\"Happy Coding!\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">private<\/span> String s = <span class=\"hljs-string\">\"Hello, world!\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">processObject<\/span><span class=\"hljs-params\">(Object obj)<\/span> <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>    System.out.println(s);           <span class=\"hljs-comment\">\/\/ Prints \"Hello, world!\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s) {\n<\/span><\/span><span class='shcb-loc'><span>      System.out.println(s);         <span class=\"hljs-comment\">\/\/ Prints \"Happy Coding!\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      System.out.println(<span class=\"hljs-keyword\">this<\/span>.s);    <span class=\"hljs-comment\">\/\/ Prints \"Hello, world!\"<\/span>\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-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\">Was gibt dieses Programm aus?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In Zeile 10 wird das in Zeile 7 definierte Feld <code>s<\/code> ausgegeben.<\/li>\n\n\n\n<li>In Zeile 12 wird die im <code>instanceof<\/code>-Ausdruck zugewiesene Variable <code>s<\/code> ausgegeben, also das auf einen String gecastete, der Methode \u00fcbergebene Objekt <code>obj<\/code>.<\/li>\n\n\n\n<li>Um innerhalb des <code>if<\/code>-Blocks auf das <em>Feld<\/em> <code>s<\/code> zuzugreifen, wird in Zeile 13 <code>this.s<\/code> verwendet.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Nicht erlaubt ist es eine Pattern-Matching-Variable so zu benennen wie eine bereits in der Methode definierte Variable, wie in folgendem Beispiel:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">processObject<\/span><span class=\"hljs-params\">(Object obj)<\/span> <\/span>{\n  String s = <span class=\"hljs-string\">\"Hello, world\"<\/span>;\n  <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s) {  <span class=\"hljs-comment\">\/\/ Compiler error <\/span>\n    <span class=\"hljs-comment\">\/\/ ...<\/span>\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Der Compiler bricht hier mit der Fehlermeldung \"Variable 's' is already defined in the scope\" ab.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Pattern Matching for instanceof \u2013 \u00c4nderungen in Java 16 <\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Gegen\u00fcber den ersten zwei Previews in <a href=\"\/de\/java\/java-14-features\/#Pattern_Matching_for_instanceof_Preview\">Java 14<\/a> und <a href=\"\/de\/java\/java-15-features\/#Pattern_Matching_for_instanceof_Second_Preview\">Java 15<\/a> wurden f\u00fcr das finale Release zwei Verfeinerungen vorgenommen:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1. Pattern-Variablen sind nicht mehr implizit final, d. h. sie k\u00f6nnen ver\u00e4ndert werden. Der folgende Code ist in Java 16 erlaubt; in Java 15 f\u00fchrte er noch zu einem \"pattern binding may not be assigned\" Compiler-Fehler:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s &amp;&amp; s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n  s = s.toUpperCase();  <span class=\"hljs-comment\">\/\/ Compiler error in Java 15, allowed in Java 16<\/span>\n  System.out.println(s);\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer i) {\n  i = i * i;            <span class=\"hljs-comment\">\/\/ Compiler error in Java 15, allowed in Java 16<\/span>\n  System.out.println(i);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">2. Ein \"Pattern Matching for instanceof\"-Ausdruck f\u00fchrt zu einem Compiler-Fehler, wenn ein Ausdruck des Typs S mit einem Pattern des Typs T verglichen wird, wobei S ein Subtyp von T ist. Hier auch daf\u00fcr ein 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\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">processInteger<\/span><span class=\"hljs-params\">(Integer i)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (i <span class=\"hljs-keyword\">instanceof<\/span> Number n) {  <span class=\"hljs-comment\">\/\/ Compiler error in Java 16<\/span>\n    <span class=\"hljs-comment\">\/\/ ...<\/span>\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Die konkrete Fehlermeldung in diesem Beispiel lautet \"pattern type Number is a subtype of expression type Integer\". Was genau bedeutet das?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Da <code>Integer<\/code> von <code>Number<\/code> erbt, sind sowohl der <code>instanceof<\/code>-Check als auch der Cast auf <code>Number<\/code> \u00fcberfl\u00fcssig. Das <code>Integer<\/code>-Objekt kann auch ohne Cast an allen Stellen eingesetzt werden, an denen <code>Number<\/code> erwartet wird.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Pattern Matching \u2013 Ausblick<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Im n\u00e4chsten Release, <a href=\"\/de\/java\/java-17-features\/#Pattern_Matching_for_switch_Preview\">Java 17<\/a>, wird die n\u00e4chste Pattern-Matching-Funktion, \"Pattern Matching for switch\" als Preview-Feature erstmals ver\u00f6ffentlicht werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"records\">Records<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ebenfalls produktionsreif \u2013 und das ebenfalls nach zwei Preview-Runden \u2013 sind in Java 16 die Records.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Records bieten eine kompakte Notationsm\u00f6glichkeit, um Klassen mit ausschlie\u00dflich finalen Feldern zu definieren, wie in folgendem Beispiel:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\">record <span class=\"hljs-title\">Point<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">int<\/span> x, <span class=\"hljs-keyword\">int<\/span> y)<\/span> <\/span>{}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-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\">Was genau Records sind, wie man sie implementiert und verwendet, wie man sie um zus\u00e4tzliche Funktionen erweitert und welche Besonderheiten bei ihnen zu beachten sind (z. B. bei der Vererbung oder der Deserialisierung) liest du aufgrund des Themenumfangs in einem separaten Artikel: <a href=\"\/de\/java\/java-records\/\">Records in Java<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(Records wurden erstmal als&nbsp;<a href=\"\/de\/java\/java-14-features\/#Records_Preview\">Preview-Feature in Java 14<\/a>&nbsp;vorgestellt. Im zweiten Preview wurden <a href=\"\/de\/java\/java-15-features\/#Records_Second_Preview\">in Java 15 einige Verfeinerungen<\/a> vorgenommen. Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/395\" target=\"_blank\">JDK Enhancement Proposal 395<\/a>&nbsp;wurden Records mit einer weiteren \u00c4nderung \u2013 sie d\u00fcrfen jetzt auch innerhalb von inneren Klassen definiert werden \u2013 als produktionsreif eingestuft.)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"migrate-from-mercurial-to-git-migrate-to-github\">Migrate from Mercurial to Git + Migrate to GitHub<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bisher wurde Java mit dem Versionskontrollsystem Mercurial entwickelt. Durch das <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/357\" target=\"_blank\">JDK Enhancement Proposal 357<\/a> wurde der Java-Quellcode zu Git migriert. Daf\u00fcr gab es mehrere Gr\u00fcnde:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verbreitung: Mit Git sind weitaus mehr Entwickler vertraut als mit Mercurial. Der Umstieg soll es f\u00fcr die Developer Community attraktiver machen sich an der JDK-Entwicklung zu beteiligen.<\/li>\n\n\n\n<li>Gr\u00f6\u00dfe der Metadaten: Das Mercurial-Repository ben\u00f6tigt etwa 1,2 GB an Metadaten. Git kommt mit nur 300 MB aus, spart also Plattenplatz und Downloadzeit. Dar\u00fcber hinaus bietet Git mit dem Parameter <code>--depth<\/code> sogenanntes \"Shallow Cloning\", wobei nur ein Teil der Commit-Historie geklont wird. <\/li>\n\n\n\n<li>Tools: Git-Support ist in jede IDE und zahlreiche Texteditoren integriert. Und es gibt grafische Tools f\u00fcr alle Betriebssysteme.<\/li>\n\n\n\n<li>Hosting: Es steht eine gro\u00dfe Auswahl an Git-Hosting-Anbietern zur Verf\u00fcgung.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Bleiben wir beim Thema Hosting: Im <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/369\" target=\"_blank\">JDK Enhancement Proposal 369<\/a> wurde entschieden das <a href=\"https:\/\/github.com\/openjdk\/\" target=\"_blank\" rel=\"noopener\">JDK auf GitHub<\/a> zu hosten. Die Gr\u00fcnde daf\u00fcr sind:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GitHub bietet hervorragende Performance.<\/li>\n\n\n\n<li>GitHub ist der weltweit gr\u00f6\u00dfte Git-Hoster.<\/li>\n\n\n\n<li>GitHub verf\u00fcgt \u00fcber eine umfassende API.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Die GitHub-API wiederum wird von zahlreichen IDEs angebunden und erm\u00f6glicht es z. B. Pull Requests direkt in der IDE zu erstellen, zu reviewen und zu kommentieren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"warnings-for-value-based-classes\">Warnings for Value-Based Classes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr die Beschreibung dieses JEPs muss ich etwas ausholen:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/valhalla\/\" target=\"_blank\">Project Valhalla<\/a> steht f\u00fcr eine Erweiterung von Java um sogenannte Value Types: Unver\u00e4nderliche Objekte, die im Speicher durch ihren Wert repr\u00e4sentiert sind \u2013 und nicht durch eine Referenz auf eine Objekt-Instanz (analog zu den primitiven Datentypen wie <code>int<\/code>, <code>long<\/code> und <code>double<\/code>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Value Types werden demzufolge keinen Konstruktor haben, der bei jedem Aufruf eine neue Instanz mit eindeutiger Identit\u00e4t erstellt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Value-Type-Instanzen, die per <code>equals()<\/code> als gleich identifiziert werden, werden auch per <code>==<\/code> als identisch gelten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a href=\"https:\/\/openjdk.org:443\/jeps\/390\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 390<\/a> wurden existierende Klassen des JDK als Kandidaten f\u00fcr zuk\u00fcnftige Value Types identifiziert. Diese wurden mit der neuen Annotation <code>@ValueBased<\/code> versehen und deren Konstruktoren als \"deprecated for removal markiert\".<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dazu geh\u00f6ren u. a.:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>alle Wrapper-Klassen der primitiven Datentypen (<code>Byte<\/code>, <code>Short<\/code>, <code>Integer<\/code>, <code>Long<\/code>, <code>Float<\/code>, <code>Double<\/code>, <code>Boolean<\/code> und <code>Character<\/code>),<\/li>\n\n\n\n<li><code>Optional<\/code> und dessen primitive Varianten,<\/li>\n\n\n\n<li>Zahlreiche Klassen der Date\/Time-API, wie z. B. <code>LocalDateTime<\/code>,<\/li>\n\n\n\n<li>die durch <code>List.of()<\/code>, <code>Set.of()<\/code> und <code>Map.of()<\/code> erzeugten Collections.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Eine vollst\u00e4ndige Liste aller als <code>@ValueBased<\/code> markierten Klassen findest du im oben verlinkten JEP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ohne Identit\u00e4t k\u00f6nnen diese Objekte nicht mehr als Monitore f\u00fcr die Synchronisation verwendet werden. Daher werden ab Java 16 Warnungen ausgegeben, wenn auf Instanzen dieser Objekte synchronisiert wird.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Zukunft (wann genau, steht noch nicht fest \u2013 in <a href=\"\/de\/java\/java-18-features\/\">Java 18<\/a> wird es noch nicht so weit sein) werden die Konstruktoren vollst\u00e4ndig entfernt werden, und der Versuch auf Value Types zu synchronisieren wird zu einem Compiler-Fehler oder zu einer Exception f\u00fchren.<\/p>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"strongly-encapsulate-jdk-internals-by-default\">Strongly Encapsulate JDK Internals by Default<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 9 wurde das Modulsystem (<a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/jigsaw\/\" target=\"_blank\">Project Jigsaw<\/a>) eingef\u00fchrt. Die meisten Programme liefen ohne gro\u00dfe Anpassungen weiter. Wir mussten maximal einige Java-EE-Dependencies hinzuf\u00fcgen, die seither nicht mehr Teil von Java SE sind.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Vor Java 16: Relaxed Strong Encapsulation<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Der Grund f\u00fcr die problemslose Migration ist, dass die JDK-Entwickler uns f\u00fcr eine \u00dcbergangszeit den sogenannten \"Relaxed strong encapsulation\"-Modus zur Verf\u00fcgung gestellt haben.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dieser Modus bedeutet, dass alle Packages, die es schon <em>vor<\/em> Java 9 gab, f\u00fcr alle unbenannten Module offen f\u00fcr Deep Reflection sind \u2013 also den Zugriff auf nicht-\u00f6ffentliche Klassen und Methoden per <code>setAccessible(true)<\/code>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Seit Java 16: Strong Encapsulation<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 16 existiert dieser Modus zwar noch, ist aber standardm\u00e4\u00dfig deaktiviert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Java 16 l\u00e4uft stattdessen im \"Strong encapsulation\"-Modus, d. h. dass jeglicher Zugriff auf nicht-\u00f6ffentliche Klassen und Methoden untersagt ist, sofern er nicht explizit per \"opens\" in der Moduldeklaration oder \"--add-opens\" auf der Kommandozeile erlaubt wird.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Von daher ist es, wenn du auf Java 16 aktualisierst, gut m\u00f6glich, dass du Fehlermeldungen dieser Art sehen wirst:<\/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.lang.reflect.InaccessibleObjectException:\n    Unable to make java.lang.invoke.MethodHandles$Lookup(java.lang.Class) accessible:\n    module java.base does not \"opens java.lang.invoke\" to unnamed module @2de8da52<\/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 class=\"wp-block-paragraph\">In diesem Beispiel bedeutet das, dass der Code versucht, den paket-privaten Konstruktor <code>Lookup(Class lookupClass)<\/code> der inneren Klasse <code>MethodHandles$Lookup<\/code> \u00fcber Reflection zug\u00e4nglich zu machen. Das ist im \"Strong encapsulation\"-Modus nicht mehr erlaubt. Du musst dies nun explizit mit \"--add-opens\" erlauben. Die Syntax lautet:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>--add-opens module\/package=target-module(,target-module)*<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Was muss man anstelle der Platzhalter \"module\", \"package\" und \"target-module\" eintragen?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Du kannst diese Werte quasi direkt aus der letzten Zeile der Fehlermeldung \u00fcbernehmen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>module: \"java.base\"<\/li>\n\n\n\n<li>package: \"java.lang.invoke\"<\/li>\n\n\n\n<li>target-module: Wenn du ein Modul f\u00fcr deinen Code definiert hast, steht am Ende der Fehlermeldung der Modulname. Ansonsten steht dort \"unnamed module\" gefolgt von einem Hashwert. Als \"target-module\" tr\u00e4gst du, wenn vorhanden, den Modulnamen ein, ansonsten \"ALL-UNNAMED\". (Den konkreten Hashwert \"@2de8da52\" kannst du nicht verwenden, da dieser sich bei jedem Start der Anwendung \u00e4ndert.)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u00dcbertragen wir die Werte aus der Fehlermeldung, dann lautet die anzugebende VM-Option:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>--add-opens java.base\/java.lang.invoke=ALL-UNNAMED<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Und wenn ich diese Option nicht angeben will und stattdessen lieber den alten Modus zur\u00fcckhaben m\u00f6chte?<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">VM-Option --illegal-access<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u00dcber die VM-Option \"--illegal-access\" kannst du das bisherige Verhalten wiederherstellen. Folgende Modi kannst du dar\u00fcber einstellen:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td><code class=\"nowrap\">--illegal-access=deny<\/code><\/td><td>\"Strong encapsulation\":<br>Deep Reflection von anderen Modulen aus ist grunds\u00e4tzlich verboten (Standardeinstellung in Java 16).<\/td><\/tr><tr><td><code class=\"nowrap\">--illegal-access=permit<\/code><\/td><td>\"Relaxed strong encapsulation\":<br>Deep Reflection von anderen Modulen auf Packages, die vor Java 9 existierten, ist erlaubt. Beim ersten Zugriff wird eine Warnung ausgegeben. Deep Reflection auf Packages, die seit Java 9 hinzugef\u00fcgt wurden, ist verboten (Standardeinstellung von Java 9 bis 15).<\/td><\/tr><tr><td><code class=\"nowrap\">--illegal-access=warn<\/code><\/td><td>Wie \"permit\", allerdings wird nicht nur beim ersten, sondern bei jedem Zugriff eine Warnung ausgegeben.<\/td><\/tr><tr><td><code class=\"nowrap\">--illegal-access=debug<\/code><\/td><td>Wie \"warn\" mit zus\u00e4tzlicher Ausgabe eines Stack Traces.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Ich rate dir allerdings dringend davon ab diese VM-Option einzusetzen. Bereits im n\u00e4chsten Release, <a href=\"\/de\/java\/java-17-features\/#Strongly_Encapsulate_JDK_Internals\">Java 17<\/a>, wird sie nicht mehr zur Verf\u00fcgung stehen, und es wird nur noch den Modus \"Strong encapsulation\" geben.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(Die standardm\u00e4\u00dfige Aktivierung von \"Strong Encapsulation\" ist im <a href=\"https:\/\/openjdk.org:443\/jeps\/396\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 396<\/a> definiert.)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"neue-stream-methoden\">Neue Stream-Methoden<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Java 16 f\u00fchrt die folgenden zwei neuen <code>Stream<\/code>-Methoden ein:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"stream-tolist\">Stream.toList()<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Um einen Stream in eine Liste zu terminieren, waren bisher folgende Varianten m\u00f6glich:<\/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-comment\">\/\/ ArrayList:<\/span>\nStream.of(<span class=\"hljs-string\">\"foo\"<\/span>, <span class=\"hljs-string\">\"bar\"<\/span>, <span class=\"hljs-string\">\"baz\"<\/span>).collect(Collectors.toList());\n\n<span class=\"hljs-comment\">\/\/ ImmutableCollections$ListN:<\/span>\nStream.of(<span class=\"hljs-string\">\"foo\"<\/span>, <span class=\"hljs-string\">\"bar\"<\/span>, <span class=\"hljs-string\">\"baz\"<\/span>).collect(Collectors.toUnmodifiableList());\n\n<span class=\"hljs-comment\">\/\/ LinkedList:<\/span>\nStream.of(<span class=\"hljs-string\">\"foo\"<\/span>, <span class=\"hljs-string\">\"bar\"<\/span>, <span class=\"hljs-string\">\"baz\"<\/span>).collect(Collectors.toCollection(LinkedList::<span class=\"hljs-keyword\">new<\/span>));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Die R\u00fcckgabetypen der ersten zwei Varianten sind nicht garantiert. Bei der ersten Variante <code>Collectors.toList()<\/code> wird tats\u00e4chlich nicht einmal garantiert, dass die Liste modifizierbar ist. Bei der zweiten Variante <code>Collectors.toUnmodifiableList()<\/code> wird zumindest garantiert, dass der R\u00fcckgabewert eine unmodifizierbare Liste ist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mit <code>Stream.toList()<\/code> kommt eine vierte Variante hinzu, die ebenfalls eine unmodifizierbare Liste generiert:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-comment\">\/\/ ImmutableCollections$ListN:<\/span>\nStream.of(<span class=\"hljs-string\">\"foo\"<\/span>, <span class=\"hljs-string\">\"bar\"<\/span>, <span class=\"hljs-string\">\"baz\"<\/span>).toList();<\/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 class=\"wp-block-paragraph\">Diese Methode ist als Default-Methode im <code>Stream<\/code>-Interface implementiert und wird in den meisten Stream-Implementierungen durch eine Stream-spezifische Optimierung \u00fcberschrieben, <\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"stream-mapmulti\">Stream.mapMulti()<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Um in einem Stream enthaltene Collections in eine einzige Collection zu mergen, benutzen wir in der Regel <code>flatMap()<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Stream&lt;List&lt;Integer&gt;&gt; stream =\n    Stream.of(\n        List.of(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span>),\n        List.of(<span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">6<\/span>),\n        List.of(<span class=\"hljs-number\">7<\/span>, <span class=\"hljs-number\">8<\/span>, <span class=\"hljs-number\">9<\/span>));\n\nList&lt;Integer&gt; list = stream.flatMap(List::stream).toList();<\/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\">Als Parameter f\u00fcr <code>flatMap()<\/code> m\u00fcssen wir eine Mapper-Funktion angeben, die jede im Stream enthaltene Collection wiederum in einen Stream konvertiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dieses Beispiel war stark vereinfacht. Der Stream muss nicht direkt Collections enthalten. Er k\u00f6nnte z. B. auch <code>Customer<\/code>-Objekte enthalten, deren <code>getOrders()<\/code>-Methode eine Liste von Bestellungen zur\u00fcckgibt. Mit <code>flatMap()<\/code> k\u00f6nnten wir dann eine Liste aller Bestellungen der Kunden zusammenstellen:<\/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\">List&lt;Customer&gt; customers = getCustomers();\nList&lt;Order&gt; allOrders = customers.stream()\n        .flatMap(customer -&gt; customer.getOrders().stream())\n        .toList();<\/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 class=\"wp-block-paragraph\">Beide Beispiele haben gemeinsam, dass f\u00fcr jedes Element des urspr\u00fcnglichen Streams ein neuer Stream generiert wird. Das ist mit einem gewissen Overhead verbunden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Daher wurde in Java 16 mit <code>Stream.mapMulti()<\/code> eine effizientere, imperative Alternative zum deklarativen <code>flatMap()<\/code> eingef\u00fchrt: W\u00e4hrend wir bei <code>flatMap()<\/code> festlegen, <em>welche<\/em> Daten wir zusammenf\u00fchren wollen, implementieren wir bei <code>mapMulti()<\/code>, <em>wie<\/em> wir diese Daten zusammenf\u00fchren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dazu \u00fcbergeben wir einen <code>BiConsumer<\/code>, dem w\u00e4hrend des Mapping-Vorgangs folgende zwei Elemente \u00fcbergeben werden:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Das Element des Streams, also die einzusammelnde Collection (die Liste im ersten Beispiel) oder das Objekt, aus dem eine Collection extrahiert wird (der <code>Customer<\/code> im zweiten Beispiel).<\/li>\n\n\n\n<li>Einen <code>Consumer<\/code>, dem wir die Elemente der Collection einzeln \u00fcbergeben.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Hier das erste Beispiel konvertiert zu <code>mapMulti()<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">List&lt;Integer&gt; list = stream\n        .mapMulti(\n            (List&lt;Integer&gt; numbers, Consumer&lt;Integer&gt; consumer) -&gt;\n                numbers.forEach(number -&gt; consumer.accept(number)))\n        .toList();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Den Lambda-Body k\u00f6nnen wir durch eine einzelne Methodenreferenz ersetzen:<\/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\">List&lt;Integer&gt; list = stream\n        .mapMulti((BiConsumer&lt;List&lt;Integer&gt;, Consumer&lt;Integer&gt;&gt;) Iterable::forEach)\n        .toList();<\/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 class=\"wp-block-paragraph\">Was wir hier sagen ist: Iteriere jeweils \u00fcber die Elemente der im Stream enthaltenen Listen, und \u00fcbergebe alle Einzelelemente an den bereitgestellten <code>Consumer<\/code>. Der Zwischenschritt \u00fcber die Erzeugung eines neuen Streams pro Liste entf\u00e4llt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Und hier das zweite Beispiel:<\/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\">List&lt;Order&gt; allOrders = customers.stream()\n        .mapMulti(\n            (Customer customer, Consumer&lt;Order&gt; consumer) -&gt;\n                customer.getOrders().forEach(consumer))\n        .toList();<\/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 class=\"wp-block-paragraph\">Wir iterieren \u00fcber die Bestellungen jedes Kunden und \u00fcbergeben diese an den bereitgestellten <code>Consumer<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sollte man nun immer <code>mapMulti()<\/code> statt <code>flatMap()<\/code> einsetzen? Nein, <code>mapMulti()<\/code> ist lediglich ein weiteres Tool in unserem Werkzeugkasten. Wir sollten generell nicht vorzeitig optimieren und diejenige Methode einsetzen, die im jeweiligen Fall am besten lesbar ist. In den Beispielen oben w\u00fcrde ich bei <code>flatMap()<\/code> bleiben. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sollte sich der Code, der <code>flatMap()<\/code> aufruft, als Hotspot erweisen, kann man testen, ob <code>mapMulti()<\/code> zu einer messbaren Leistungssteigerung f\u00fchrt und, nur wenn dem so ist, umstellen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"packaging-tool\">Packaging Tool<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Seit der in Java 8 eingef\u00fchrte <code>javapackager<\/code> mitsamt JavaFX in <a href=\"\/de\/java\/java-11-features\/#JavaFX_geht_eigene_Wege\">Java 11<\/a> wieder entfernt wurde, wartete die Java-Community sehnlichst auf Ersatz.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Als Nachfolger wurde in <a href=\"\/de\/java\/java-14-features\/#Packaging_Tool_Incubator\">Java 14<\/a> das Tool <code>jpackage<\/code> im Incubator-Status pr\u00e4sentiert. Mit dem <a href=\"https:\/\/openjdk.org:443\/jeps\/392\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 392<\/a> wird <code>jpackage<\/code> in Java 16 als produktionsreif eingestuft.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>jpackage<\/code> verpackt eine Java-Anwendung mitsamt der Java-Laufzeitumgebung (also der JVM und der Klassenbibliothek*) in ein Installationspaket f\u00fcr verschiedene Betriebssysteme, um Endbenutzern ein einfaches und f\u00fcr sie nat\u00fcrliches Installationserlebnis zu bieten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unterst\u00fctzt werden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Windows (exe und msi) <\/li>\n\n\n\n<li>macOS (pkg und dmg)<\/li>\n\n\n\n<li>Linux (deb und rpm)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">(* Bei einer Anwendung, die das Java-Modulsystem nutzt, wird die Klassenbibliothek auf die tats\u00e4chlich genutzten Module komprimiert.)<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Verwendung von jpackage<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Das folgende Beispiel zeigt, wie ein minimales, nicht-modulares Java-Programm compiliert und mit <code>jpackage<\/code> in einen Installer des aktuell genutzten Betriebssystems verpackt wird.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die folgende Datei <code>Main.java<\/code> liegt im Verzeichnis <code>src\/eu\/happycoders<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">package<\/span> eu.happycoders;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Main<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n    System.out.println(<span class=\"hljs-string\">\"Happy Coding!\"<\/span>);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Wir compilieren die Datei wie folgt (die letzten zwei Zeilen musst du unter Windows als eine Zeile schreiben):<\/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\">javac -d target\/classes src\/eu\/happycoders\/Main.java\njar cf lib\/happycoders.jar -C target\/classes .\njpackage --name happycoders --input lib \\\n    --main-jar happycoders.jar --main-class eu.happycoders.Main<\/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\">Unter Windows wird dadurch der ausf\u00fchrbare Installer <code>happycoders-1.0.exe<\/code> erstellt, unter Debian-Linux das Software-Paket <code>happycoders_1.0-1_amd64.deb<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mit der Option <code>--type<\/code> kann ein anderes Format erstellt werden, unter macOS z. B. eine <code>pkg<\/code>-Datei anstelle der standarm\u00e4\u00dfigen <code>dmg<\/code>-Datei:<\/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\">jpackage --name happycoders --input lib \\\n    --main-jar happycoders.jar --main-class eu.happycoders.Main --type pkg<\/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\">Die Erzeugung von Installern f\u00fcr andere als das aktuell eingesetzte Betriebssystem wird nicht unterst\u00fctzt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Weitere jpackage-Optionen<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Wie du <code>jpackage<\/code> f\u00fcr eine modulare Anwendung verwendest und welche weiteren Optionen das Tool bietet, findest du in der <a rel=\"noopener\" href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/16\/docs\/specs\/man\/jpackage.html\" target=\"_blank\">jpackage-Dokumentation<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"performance-verbesserungen\">Performance-Verbesserungen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Java 16 bringt Performance-Verbesserungen an den Garbage Collectoren und am Metaspace und erlaubt eine effizientere Interprozesskommunikation \u00fcber die neu unterst\u00fctzten Unix-Domain-Sockets.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zgc-concurrent-thread-stack-processing\">ZGC: Concurrent Thread-Stack Processing<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ziel des in <a href=\"\/de\/java\/java-15-features\/#Neue_Garbage_Collectoren_ZGC_Shenandoah\">Java 15<\/a> final ver\u00f6ffentlichten Z Garbage Collectors (ZGC) ist es, Stop-the-World-Phasen so kurz wie m\u00f6glich (d. h. im einstelligen Millisekundenbereich) zu halten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Erreicht werden soll das, indem m\u00f6glichst viele Operationen des Garbage Collectors aus den sogenannten Safepoints (w\u00e4hrend derer die Anwendung angehalten wird) herausgenommen und parallel zur Anwendung ausgef\u00fchrt werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mit dem <a href=\"https:\/\/openjdk.org:443\/jeps\/376\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 376<\/a> wird nun auch die letzte dieser Operationen, das sogenannte \"Thread-Stack Processing\", aus den Safepoints entfernt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Safepoints sind damit auf das absolut Notwendige reduziert. Sie erhalten keine Operationen mehr, deren Ausf\u00fchrungszeit mit der Gr\u00f6\u00dfe des Heaps skaliert. Die Stop-the-World-Phasen des ZGC dauern nun in der Regel weniger als eine Millisekunde, unabh\u00e4ngig von der Heap-Gr\u00f6\u00dfe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Weitere Details findest du im oben verlinkten JEP und im <a href=\"https:\/\/wiki.openjdk.org\/spaces\/zgc\/overview\" target=\"_blank\" rel=\"noreferrer noopener\">ZGC-Wiki<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"concurrently-uncommit-memory-in-g1\">Concurrently Uncommit Memory in G1<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Die Bestimmung, wie viel Speicher der G1 Garbage Collector an das Betriebssystem zur\u00fcckgibt, und die eigentliche R\u00fcckgabe erfolgte bisher in einer Stop-the-World-Pause.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dies wurde dahingehend optimiert, dass nur noch die Berechnung w\u00e4hrend der Pause stattfindet, die eigentliche Freigabe aber parallel zur Anwendung l\u00e4uft.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(F\u00fcr diese Optimierung gibt es kein JDK Enhancement Proposal.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"elastic-metaspace\">Elastic Metaspace<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Im sogenannten \"Metaspace\" speichert die JVM Klassen-Metadaten, also alle Informationen <em>\u00fcber<\/em> eine Klasse, wie z. B. die Elternklasse, Methoden und Feldnamen \u2013 nicht aber den Inhalt der Felder (der liegt auf dem Heap).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ja nach Anwendungsprofil kann der Metaspace einen \u00fcberm\u00e4\u00dfig hohen Speicherverbrauch aufweisen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/387\" target=\"_blank\">JDK Enhancement Proposal 387<\/a> wird der Memory-Footprint generell gesenkt, und Metaspace-Speicher wird schneller ans Betriebssystem zur\u00fcckgegeben. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dar\u00fcber hinaus wurde der Quellcode f\u00fcr die Verwaltung des Metaspace vereinfacht, um die Maintenance-Kosten zu reduzieren.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"unix-domain-socket-channels\">Unix-Domain Socket Channels<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Unix-Domain-Sockets werden f\u00fcr die Interprozesskommunikation (IPC) innerhalb eines Hosts verwendet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sie \u00e4hneln TCP\/IP-Sockets, werden aber \u00fcber Dateisystem-Pfade adressiert, nicht \u00fcber IP-Adressen. Sie sind sicherer (kein Zugriff von au\u00dferhalb des Hosts m\u00f6glich) und bieten einen schnelleren Verbindungsaufbau und einen h\u00f6heren Datendurchsatz als TCP\/IP-Loopback-Verbindungen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch den <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/380\" target=\"_blank\">JDK Enhancement Proposal 380<\/a> k\u00f6nnen nun auch Java-Entwicklerinnen und -Entwickler Unix-Domain-Sockets einsetzen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Aus Programmiersicht \u00e4ndert sich wenig im Vergleich zu TCP\/IP-Sockets: Die Unix-Domain-Socket-Unterst\u00fctzung wurde in die bestehenden <a rel=\"noopener\" href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/16\/docs\/api\/java.base\/java\/nio\/channels\/SocketChannel.html\" target=\"_blank\">SocketChannel<\/a>- und <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/16\/docs\/api\/java.base\/java\/nio\/channels\/ServerSocketChannel.html\" target=\"_blank\" rel=\"noopener\">ServerSocketChannel<\/a>-APIs integriert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das folgende (sehr rudiment\u00e4re) Beispiel zeigt, wie ein TCP\/IP-Server-Socket auf Port 8080 ge\u00f6ffnet wird und wie ein Client sich mit diesem Server verbindet:<\/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\">var<\/span> socketAddress = <span class=\"hljs-keyword\">new<\/span> InetSocketAddress(<span class=\"hljs-number\">8080<\/span>);\n\n<span class=\"hljs-comment\">\/\/ Server<\/span>\n<span class=\"hljs-keyword\">var<\/span> serverSocketChannel = ServerSocketChannel.open();\nserverSocketChannel.bind(socketAddress);\n\n<span class=\"hljs-comment\">\/\/ Client<\/span>\n<span class=\"hljs-keyword\">var<\/span> socketChannel = SocketChannel.open();\nsocketChannel.connect(remoteAddress);<\/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\">Und hier das analoge Beispiel mit dem Unix-Domain-Socket-Pfad \"~\/happycoders.socket\":<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">var<\/span> socketPath = Path.of(System.getProperty(<span class=\"hljs-string\">\"user.home\"<\/span>)).resolve(<span class=\"hljs-string\">\"happycoders.socket\"<\/span>);\n<span class=\"hljs-keyword\">var<\/span> socketAddress = UnixDomainSocketAddress.of(socketPath);\n\n<span class=\"hljs-comment\">\/\/ Server<\/span>\n<span class=\"hljs-keyword\">var<\/span> serverSocketChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);\nserverSocketChannel.bind(socketAddress);\n\n<span class=\"hljs-comment\">\/\/ Client<\/span>\n<span class=\"hljs-keyword\">var<\/span> socketChannel = SocketChannel.open(StandardProtocolFamily.UNIX);\nsocketChannel.connect(remoteAddress);<\/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\">Du musst also lediglich beim \u00d6ffnen eines Channels den Typ <code>StandardProtocolFamily.UNIX<\/code> angeben und eine Adresse vom Typ <code>UnixDomainSocketAddress<\/code> anstelle von <code>InetSocketAddress<\/code> verwenden. Die weitere Arbeit mit dem Channel ist f\u00fcr beide Typen gleich.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unix-Domain-Sockets sind \u00fcbrigens nicht auf Unix-Plattformen beschr\u00e4nkt; sie werden auch von Windows 10 und Windows Server 2019 unterst\u00fctzt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"experimentelle-preview-und-incubator-features\">Experimentelle, Preview- und Incubator-Features<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Seit Java 10 wird alle sechs Monate ein neues Java-Release ver\u00f6ffentlicht. So k\u00f6nnen neue Features in nicht-finalem Zustand mit ausgeliefert und getestet werden. Die Java-Community kann dann Feedback geben, das bei der Weiterentwicklung der Features ber\u00fccksichtigt wird.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Auch in Java 16 gibt es weiterentwickelte und neue Preview- und Incubator-Features. Ich werde insbesondere die Incubator-Features nicht detailliert vorstellen, sondern, soweit bekannt, auf die Java-Version verweisen, in der diese Features Produktionsreife erlangen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sealed-classes-second-preview\">Sealed Classes (Second Preview)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sealed Classes wurden <a href=\"\/de\/java\/java-15-features\/#Sealed_Classes_Preview\">in Java 15 als Preview<\/a> vorgestellt. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/397\" target=\"_blank\">JDK Enhancement Proposal 397<\/a> wurden f\u00fcr Java 16 drei kleine \u00c4nderungen vorgenommen:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1. In der Java Language Specification (JLS) ersetzt das Konzept der \"contextual keyword\" die bisherigen \"restricted identifiers\" and \"restricted keywords\". \"Contextual keywords\" sorgen daf\u00fcr, dass neue Keywords wie <code>sealed<\/code>, <code>permits<\/code> (oder <code>yield<\/code> aus den <a href=\"\/de\/java\/java-14-features\/#Switch_Expressions_Standard\">Switch Expressions<\/a>) au\u00dferhalb des jeweiligen Kontexts z. B. als Variablen- oder Methodennamen weiterhin verwendet werden d\u00fcrfen. So muss bestehender Code beim Upgrade auf eine neue Java-Version nicht ge\u00e4ndert werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Folgendes ist also erlaubt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">sealed<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n  <span class=\"hljs-keyword\">int<\/span> permits = <span class=\"hljs-number\">5<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">2. Das Keyword \"permits\" kann weggelassen werden, wenn innerhalb einer Klassendatei (\"compilation unit\") von einer versiegelten Klasse abgeleitete Unterklassen definiert werden. Diese gelten dann als \"implizit deklarierte zul\u00e4ssige Unterklassen\" (\"implicitly declared permitted subclasses\").<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein Beispiel daf\u00fcr findest du im <a href=\"\/de\/java\/sealed-classes\/#Versiegelung_innerhalb_einer_Compilation_Unit\">Artikel \u00fcber Sealed Classes<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Was im zweiten Preview von Sealed Classes ge\u00e4ndert wurde, ist, dass lokale (also innerhalb von Methoden definierte) Klassen versiegelte Klassen <em>nicht<\/em> erweitern d\u00fcrfen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Auch daf\u00fcr findest du ein Beispiel im <a href=\"\/de\/java\/sealed-classes\/#Lokale_Klassen\">Artikel \u00fcber Sealed Classes<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">3. Bei <code>instanceof<\/code>-Tests pr\u00fcft der Compiler, ob die Klassenhierarchie es zul\u00e4sst, dass der Check jemals <code>true<\/code> ergeben kann. Seit dem zweiten Preview der Sealed Classes werden die Informationen aus versiegelten Klassenhierarchien mit in diese Pr\u00fcfung aufgenommen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Was das bedeutet, erkl\u00e4re ich im <a href=\"\/de\/java\/sealed-classes\/#instanceof-Tests_mit_versiegelten_Klassen\">Artikel \u00fcber Sealed Classes<\/a> an einem Beispiel.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vector-api-incubator\">Vector API (Incubator)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vector ... gibt es den nicht schon seit Java 1.0?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nein, hier geht es nicht um die <code>List<\/code>-Implementierung <code>java.util.Vector<\/code>, sondern um Vektorrechnung im mathematischen Sinn.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein Vektor entspricht im Grunde einem Array von skalaren Werten (<code>byte<\/code>, <code>short<\/code>, <code>int<\/code>, <code>long<\/code>, <code>float<\/code> oder <code>double<\/code>). In der Vektorrechnung werden skalare Operationen (z. B. Addition) auf zwei Vektoren der gleichen Gr\u00f6\u00dfe angewendet. Dabei wird diese Operation paarweise auf jedes Element der Vektoren angewendet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bei der Vektoraddition bspw. addiert man das erste Element des ersten Vektors mit dem ersten Element des zweiten Vektors, das zweite Element des ersten Vektors mit dem zweiten Element des zweiten Vektors, usw. (das kennst du vermutlich aus dem Mathe-Unterricht):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-half_400\"><img decoding=\"async\" width=\"400\" height=\"91\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-400x91.png\" alt=\"Beispiel einer Vektoraddition\" class=\"wp-image-25531\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-400x91.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-224x51.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-336x76.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-504x115.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-672x153.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition-600x137.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-vector-addition.png 800w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><figcaption class=\"wp-element-caption\">Beispiel einer Vektoraddition<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Moderne CPUs und GPUs k\u00f6nnen solche Operationen bis zu einer bestimmten Vektorgr\u00f6\u00dfe innerhalb von einem einzigen CPU-Zyklus ausf\u00fchren und damit die Leistung erheblich steigern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/338\" target=\"_blank\">JDK Enhancement Proposal 338<\/a> als Incubator-Feature erstmals vorgestellte Vektor-API erm\u00f6glicht es uns solche Operationen in Java zu implementieren. Die JVM wird diese auf die effizientesten CPU-Instruktionen der zugrunde liegenden Hardware-Architektur abbilden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Incubator-Features unterliegen in der Regel noch wesentlichen \u00c4nderungen. Ich werde die Vector-API daher dann vorstellen, wenn sie den Preview-Status erreicht hat.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"foreign-linker-api-incubator-foreign-memory-access-api-third-incubator\">Foreign Linker API (Incubator) +  Foreign-Memory Access API (Third Incubator)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Bereits seit Java 1.1 gibt es mit dem Java Native Interface (JNI) die M\u00f6glichkeit, von Java aus auf nativen C-Code zuzugreifen. Wer JNI einmal eingesetzt hat, wei\u00df: Es ist aufw\u00e4ndig, fehleranf\u00e4llig und langsam. Man muss eine Menge Java- und C-Boilerplate-Code schreiben und synchron halten, was selbst mit Tool-Unterst\u00fctzung noch kompliziert ist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Um JNI durch eine modernere API zu ersetzen, wurde <a href=\"https:\/\/openjdk.org:443\/projects\/panama\/\" target=\"_blank\" rel=\"noopener\">Project Panama<\/a> ins Leben gerufen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Foreign Linker API (<a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/389\" target=\"_blank\">JDK Enhancement Proposal 389<\/a>) zusammen mit der <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-14-features\/#Foreign-Memory_Access_API_Incubator\">in Java 14 als Incubator<\/a> vorgestellten, <a href=\"\/de\/java\/java-15-features\/#Foreign-Memory_Access_API_Second_Incubator\">in Java 15<\/a> und Java 16 noch einmal verfeinerten Foreign-Memory Access API (<a href=\"https:\/\/openjdk.org:443\/jeps\/393\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 393<\/a>) stellen diesen Ersatz dar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Panama-Entwickler haben sich folgende Ziele gesetzt:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Der bisher aufw\u00e4ndige und fehleranf\u00e4llige Prozess soll vereinfacht werden (angepeilt ist eine Reduktion um 90 % des Aufwands).<\/li>\n\n\n\n<li>Die Leistung soll im Vergleich zu JNI wesentlich erh\u00f6ht werden (angepeilt ist Faktor 4 bis 5). <\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Foreign Linker API und Foreign-Memory Access API werden in <a href=\"\/de\/java\/java-17-features\/#Foreign_Function_Memory_API_Incubator\">Java 17<\/a> zur \"Foreign Function &amp; Memory API\" zusammengefasst werden. Diese wird noch bis Java 18 im Incubator-Status bleiben und in <a href=\"\/de\/java\/java-19-features\/#Foreign_Function_Memory_API_Preview\">Java 19<\/a> das Preview-Stadium erreichen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecations\">Deprecations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 16 wurden einige Funktionen als \"deprecated\" markiert. Eine davon m\u00f6chte ich hier mit auflisten, die restlichen findest du in den <a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/16-relnote-issues.html\" target=\"_blank\" rel=\"noreferrer noopener\">Release Notes<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"terminally-deprecated-threadgroup-stop-destroy-isdestroyed-setdaemon-and-isdaemon\">Terminally Deprecated ThreadGroup stop, destroy, isDestroyed, setDaemon and isDaemon<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In <a href=\"\/java\/java-14-features\/#Thread_SuspendResume_Are_Deprecated_for_Removal\">Java 14<\/a> wurde damit begonnen <code>Thread<\/code>- und <code>ThreadGroup<\/code>-Methoden, die seit Java 1.2 \"deprecated\" sind, als \"deprecated for removal\" zu markieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 16 wurden nun auch die <code>ThreadGroup<\/code>-Methoden <code>stop()<\/code>, <code>destroy()<\/code>, <code>isDestroyed()<\/code>, <code>setDaemon()<\/code> and <code>isDaemon()<\/code> als \"deprecated for removal\" markiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Der Mechanismus zum Zerst\u00f6ren einer Thread-Gruppe war im JDK von Anfang an mangelhaft implementiert und soll in einer zuk\u00fcnftigen Version komplett entfernt werden; damit ist auch das Konzept der Daemon-Thread-Gruppe hinf\u00e4llig.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-16\">Sonstige \u00c4nderungen in Java 16<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In diesem Kapitel liste ich \u00c4nderungen auf, mit denen die meisten Java-Entwicklerinnen und -Entwickler in ihrer t\u00e4glichen Arbeit nicht in Ber\u00fchrung kommen werden. Dar\u00fcber einmal gelesen zu haben, schadet aber auch nicht :-)<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"add-invocationhandlerinvokedefault-method-for-proxys-default-method-support\">Add InvocationHandler::invokeDefault Method for Proxy's Default Method Support<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn du mit Dynamic Proxies arbeitest, wird diese Erweiterung interessant f\u00fcr dich sein. Am besten l\u00e4sst sie sich an einem Beispiel erkl\u00e4ren. Nehmen wir folgendes Interface:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">GreetingInterface<\/span> <\/span>{\n  <span class=\"hljs-function\">String <span class=\"hljs-title\">getName<\/span><span class=\"hljs-params\">()<\/span><\/span>;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">default<\/span> String <span class=\"hljs-title\">greet<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"Hello, \"<\/span> + getName();\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Mit dem folgenden Code erstellen wir daf\u00fcr einen dynamischen Proxy (das ist kein neues Feature \u2013 Dynamic Proxies gibt es seit Java 1.3):<\/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>GreetingInterface greetingProxy = (GreetingInterface) Proxy.newProxyInstance(\n<\/span><\/span><span class='shcb-loc'><span>    GreetingTest<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>.<span class=\"hljs-title\">getClassLoader<\/span>(),<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\">    <span class=\"hljs-title\">new<\/span> <span class=\"hljs-title\">Class<\/span>&#091;] <\/span>{GreetingInterface<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>},<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">    (<span class=\"hljs-title\">proxy<\/span>, <span class=\"hljs-title\">method<\/span>, <span class=\"hljs-title\">args<\/span>) -&gt; <\/span>{<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      <span class=\"hljs-keyword\">if<\/span> (method.getName().equals(<span class=\"hljs-string\">\"getName\"<\/span>)) {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"Sven\"<\/span>;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      } <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (method.getName().equals(<span class=\"hljs-string\">\"greet\"<\/span>)) {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"Hello, \"<\/span> + ((GreetingInterface) proxy).getName();<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      } <span class=\"hljs-keyword\">else<\/span> {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">        <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> IllegalStateException(<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">            <span class=\"hljs-string\">\"Method not implemented: \"<\/span> + method);<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      }<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">    });<\/span><\/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 class=\"wp-block-paragraph\"> Den dynamischen Proxy k\u00f6nnen wir dann \u00fcber die <code>GreetingInterface<\/code>-Methoden nutzen:<\/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\">System.out.println(<span class=\"hljs-string\">\"name  = \"<\/span> + greetingProxy.getName());\nSystem.out.println(<span class=\"hljs-string\">\"greet = \"<\/span> + greetingProxy.greet());<\/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\">Die Ausgabe ist:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">name  = Sven\ngreet = Hello, Sven<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Wer gut aufgepasst hat, wird feststellen, dass wir etwas Code duplizieren mussten, n\u00e4mlich die Implementierung der <code>greet()<\/code>-Methode. Diese ist einmal als Default-Methode im <code>GreetingInterface<\/code> implementiert \u2013 und noch einmal im <code>InvocationHandler<\/code>-Lambda (Zeile 8 des zweiten Listings).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 16 wurde die <code>InvocationHandler<\/code>-Klasse um die statische Methode <code>invokeDefault()<\/code> erweitert, mit der wir den duplizierten Code eliminieren und stattdessen die Default-Methode des Interfaces aufrufen k\u00f6nnen (Zeile 8):<\/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 shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>GreetingInterface greetingProxy = (GreetingInterface) Proxy.newProxyInstance(\n<\/span><\/span><span class='shcb-loc'><span>    GreetingTest<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>.<span class=\"hljs-title\">getClassLoader<\/span>(),<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\">    <span class=\"hljs-title\">new<\/span> <span class=\"hljs-title\">Class<\/span>&#091;] <\/span>{GreetingInterface<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>},<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">    (<span class=\"hljs-title\">proxy<\/span>, <span class=\"hljs-title\">method<\/span>, <span class=\"hljs-title\">args<\/span>) -&gt; <\/span>{<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      <span class=\"hljs-keyword\">if<\/span> (method.getName().equals(<span class=\"hljs-string\">\"getName\"<\/span>)) {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"Sven\"<\/span>;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      } <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (method.isDefault()) {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">        <span class=\"hljs-keyword\">return<\/span> InvocationHandler.invokeDefault(proxy, method, args);<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      } <span class=\"hljs-keyword\">else<\/span> {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">        <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> IllegalStateException(<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">            <span class=\"hljs-string\">\"Method not implemented: \"<\/span> + method);<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">      }<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-class\"><span class=\"hljs-class\">    });<\/span><\/span>\n<\/span><\/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 Zeile 7 habe ich au\u00dferdem die Pr\u00fcfung der Methode auf den Namen \"greet\" durch <code>if (method.isDefault())<\/code> ersetzt und damit den <code>if<\/code>-Zweig auf alle Default-Methoden erweitert. Somit m\u00fcssen wir den <code>InvocationHandler<\/code> nicht anpassen, sollten wir dem Interface weitere Default-Methoden hinzuf\u00fcgen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(Diese Erweiterung ist in keinem JDK Enhancement Proposal definiert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"day-period-support-added-to-java-time-formats\">Day Period Support Added to java.time Formats<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Mit der Klasse <code>DateTimeFormatter<\/code> kannst du Datumswerte der Java Date\/Time API, also z. B. <code>LocalDate<\/code>, <code>LocalTime<\/code>, <code>LocalDateTime<\/code>, oder auch <code>Instant<\/code>, <code>Year<\/code> und <code>YearMonth<\/code> formatieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Den aktuellen Zeitpunkt kannst du bspw. wie folgt formatieren:<\/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\">DateTimeFormatter.ofPattern(<span class=\"hljs-string\">\"EEEE, d. MMMM yyyy, H:mm\"<\/span>, Locale.GERMANY)\n    .format(LocalDateTime.now());<\/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\">Heraus kommt dabei z. B.:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>Mittwoch, 1. Dezember 2021, 21:12<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In manchen Gegenden ist es \u00fcblich die Uhrzeit nicht im 24-Stunden-Format anzugeben, sondern im 12-Stunden-Format und dann mit \"AM\" und \"PM\" zu kennzeichnen, um welche Tageszeit es sich handelt:<\/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\">DateTimeFormatter.ofPattern(<span class=\"hljs-string\">\"EEEE, MMMM d, yyyy, h:mm a\"<\/span>, Locale.US)\n    .format(LocalDateTime.now());<\/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\">Das ergibt folgendes:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>Wednesday, December 1, 2021, 9:14 PM<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In Java 16 wurde die Liste der verf\u00fcgbaren Format-Zeichen um den Buchstaben \"B\" erweitert. Dieser steht f\u00fcr eine ausgeschriebene Form der Tageszeit:<\/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\">DateTimeFormatter.ofPattern(<span class=\"hljs-string\">\"EEEE, MMMM d, yyyy, h:mm B\"<\/span>, Locale.US)\n    .format(LocalDateTime.now());<\/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 class=\"wp-block-paragraph\">Der erzeugte String lautet nun:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>Wednesday, December 1, 2021, 9:16 at night<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das funktioniert auch im Deutschen:<\/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\">DateTimeFormatter.ofPattern(<span class=\"hljs-string\">\"EEEE, d. MMMM yyyy, h:mm B\"<\/span>, Locale.GERMANY)\n    .format(LocalDateTime.now());<\/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\">Das ergibt die eher gew\u00f6hnungsbed\u00fcrfte Schreibweise:<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><code>Mittwoch, 1. Dezember 2021, 9:18 abends<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(F\u00fcr diese Erweiterung existiert kein JDK Enhancement Proposal.) <\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"alpine-linux-port\">Alpine Linux Port<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Das besonders im Cloud-Umfeld sehr beliebte Alpine-Linux basiert auf der C-Bibliothek \"musl\". Das bedeutet, dass Code, der gegen die in den meisten Linux-Distributionen verwendete C-Bibliothek \"glibc\" kompiliert wurde, nicht ohne weiteres auf Alpine Linux l\u00e4uft.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dazu geh\u00f6rt auch die JVM. Um diese auf Alpine laufen zu lassen, ben\u00f6tigte man bisher eine glibc-Portabilit\u00e4tsschicht.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Alpine Linux ist gerade deshalb so beliebt, weil es nur wenige Megabytes gro\u00df ist. Zusammen mit einer abgespeckten JVM-Version kann man ein Docker-Image mit nur 38 MB Gr\u00f6\u00dfe generieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die glibc-Portabilit\u00e4tsschicht w\u00fcrde dem weitere 26 MB hinzuf\u00fcgen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch den <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/386\" target=\"_blank\">JDK Enhancement Proposal 386<\/a> wird das JDK auf Alpine Linux (und alle anderen Linux-Distributionen, die \"musl\" verwenden) portiert. Damit wird die glibc-Portabilit\u00e4tsschicht nicht mehr ben\u00f6tigt, was die Docker-Images wesentlich verkleinert.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"windows-aarch64-port\">Windows\/AArch64 Port<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Auch Windows auf der ARM64\/AArch64-Prozessorarchitektur ist zu einer wichtigen Plattform geworden. Daher wurde das JDK durch den <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/388\" target=\"_blank\">JDK Enhancement Proposal 388<\/a> auf Windows\/AArch64 portiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dazu wurde der bereits seit Java 9 existierende Linux\/AArch64-Port als Grundlage genommen, so dass der Aufwand \u00fcberschaubar blieb.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"enable-c14-language-features\">Enable C++14 Language Features<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Diese \u00c4nderung ist f\u00fcr C++-Entwickler interessant, die an der Entwicklung des JDK selbst mitarbeiten wollen. Der C++-Anteil des JDK war bisher auf die Sprachspezifikation C++98\/03 \u2013 also eine \u00fcber 20 Jahre alte Spezifikation \u2013 beschr\u00e4nkt. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/347\" target=\"_blank\">JDK Enhancement Proposal 347<\/a> wird die Unterst\u00fctzung auf C++14 angehoben.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Da die Zielgruppe dieses Artikels Java-Entwickler sind, werde ich auf die Bedeutung dieser \u00c4nderung f\u00fcr die eingesetzten Build-Systeme und die im JDK zugelassenen C++-Sprachmittel nicht weiter eingehen. Du findest diese Details im oben verlinkten JEP.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-16\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 16<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In diesem Artikel habe ich alle Java-16-\u00c4nderungen vorgestellt, die in JDK Enhancement Proposals definiert sind, sowie einige Erweiterungen der JDK-Klassenbibliothek und Performance-Optimierungen, f\u00fcr die keine JEPs existieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eine vollst\u00e4ndige Liste aller \u00c4nderungen findest du in den&nbsp;<a href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/16-relnote-issues.html\" target=\"_blank\" rel=\"noopener\">offiziellen Java 16 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\">Java 16 war ein sehr umfangreiches Release:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\"Pattern Matching for instanceof\" und Records sind der Preview-Phase entwachsen und k\u00f6nnen in produktivem Code eingesetzt werden. Insbesondere mit Records wird man viele Zeilen an Boilerplate Code eliminieren k\u00f6nnen.<\/li>\n\n\n\n<li>Der Umzug auf Git und GitHub macht die Beteiligung an der JDK-Entwicklung attraktiver f\u00fcr die Developer Community.<\/li>\n\n\n\n<li>Mit \"Warnings for Value-Based Classes\" werden die ersten Schritte Richtung Value Types (<a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/valhalla\/\" target=\"_blank\">Project Valhalla<\/a>) vollzogen.<\/li>\n\n\n\n<li>\"Strong Encapsulation\" ist nun der Standard, d. h. Zugriff auf andere Module per Deep Reflection muss explizit (mit <code>opens<\/code> oder <code>--add-opens<\/code>) gestattet werden.<\/li>\n\n\n\n<li><code>Stream.toList()<\/code> und <code>Stream.mapMulti()<\/code> erweitern unseren Stream-Werkzeugkasten.<\/li>\n\n\n\n<li>Mit <code>jpackage<\/code> k\u00f6nnen wir nach der Entfernung von <code>javapackager<\/code> in Java 11 endlich wieder Installationspakete erstellen.<\/li>\n\n\n\n<li>An den Garbage Collectoren und am Metaspace wurden Performance-Verbesserungen vorgenommen, und durch die Einf\u00fchrung von Unix-Domain-Socket-Channels kann die Interprozesskommunikation innerhalb eines Hosts effizienter implementiert werden.<\/li>\n\n\n\n<li>Als weitere Incubator-Projekte kamen die Vector-API und die Foreign Linker API hinzu. <\/li>\n\n\n\n<li>Kleinere Erweiterungen der Klassenbibliothek und zwei neue Ports runden das Release ab.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn dir der Artikel gefallen hat, hinterlasse mir gerne einen Kommentar, oder teile den Artikel \u00fcber einen der Share-Butons am Ende.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wir n\u00e4hern uns mit gro\u00dfen Schritten dem n\u00e4chsten Long-Term-Support-Release, <a href=\"\/de\/java\/java-17-features\/\">Java 17<\/a>. M\u00f6chtest du informiert werden, wenn der n\u00e4chste Artikel ver\u00f6ffentlicht wird? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klick hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Alle neuen Features von Java 16 mit Beispielen: \"Pattern Matching for instanceof\", Records, Value-Based Classes, Strong Encapsulation, neue Stream-Methoden, jpackage und mehr...<\/p>\n","protected":false},"author":1,"featured_media":34266,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"Die neuen Features von Java 16 mit Beispielen: \"Pattern Matching for instanceof\", Records, Value-Based Classes, Strong Encapsulation und mehr...","_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 16,java 16 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":38932,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-25448","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-16-features.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-features.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/12\/java-16-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 16 mit Beispielen: \"Pattern Matching for instanceof\", Records, Value-Based Classes, Strong Encapsulation, neue Stream-Methoden, jpackage und mehr...","public_identification_id":"34ac7f06b37f46edb47917d50e7bf2f2","private_identification_id":"eed5c3798df34f8587b3111e2f84e826","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/25448","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=25448"}],"version-history":[{"count":11,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/25448\/revisions"}],"predecessor-version":[{"id":56047,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/25448\/revisions\/56047"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34266"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=25448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=25448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=25448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}