{"id":24048,"date":"2021-11-15T14:45:00","date_gmt":"2021-11-15T13:45:00","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=24048"},"modified":"2024-11-27T15:00:02","modified_gmt":"2024-11-27T14:00:02","slug":"java-14-features","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/java-14-features\/","title":{"rendered":"Java 14 Features (mit Beispielen)"},"content":{"rendered":"\n<p>Nachdem das vorherige Release eher klein ausgefallen war, wurde am 17. M\u00e4rz 2020 Java 14 mit eindrucksvollen 16 umgesetzten JDK Enhancement Proposals (JEPs) ver\u00f6ffentlicht.<\/p>\n\n\n\n<p>Mit Java 14 h\u00e4lt es auch wieder eine gro\u00dfe \u00c4nderung Einzug in die Sprache: Switch Expressions.<\/p>\n\n\n\n<p>Ein weiteres n\u00fctzliches Feature, \"Helpful NullPointerExceptions\", wird uns in Zukunft viel Arbeit bei der Fehlersuche abnehmen.<\/p>\n\n\n\n<p>Mit Records und \"Pattern Matching for instanceof\" sind au\u00dferdem zwei spannende Previews mit von der Partie.<\/p>\n\n\n\n<p>Wie immer gibt es auch einige Performance-Verbesserungen; und eine ganze Menge Features wurde als \"deprecated\" markiert oder entfernt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"switch-expressions-standard\">Switch Expressions (Standard)<\/h2>\n\n\n\n<p>Mit Switch Expressions erreicht die zweite Sprachverbesserung aus <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/amber\/\" target=\"_blank\">Project Amber<\/a> den Produktionsstatus (die erste war <a href=\"\/de\/java\/java-10-features\/#Local-Variable_Type_Inference_var\" data-type=\"post\">\"var\" in Java 10<\/a>). Switch Expressions erm\u00f6glichen mit der Pfeilnotation eine deutlich kompaktere Schreibweise als bisher:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">switch<\/span> (day) {\n  <span class=\"hljs-keyword\">case<\/span> MONDAY, FRIDAY, SUNDAY -&gt; System.out.println(<span class=\"hljs-number\">6<\/span>);\n  <span class=\"hljs-keyword\">case<\/span> TUESDAY                -&gt; System.out.println(<span class=\"hljs-number\">7<\/span>);\n  <span class=\"hljs-keyword\">case<\/span> THURSDAY, SATURDAY     -&gt; System.out.println(<span class=\"hljs-number\">8<\/span>);\n  <span class=\"hljs-keyword\">case<\/span> WEDNESDAY              -&gt; System.out.println(<span class=\"hljs-number\">9<\/span>);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Als Ausdruck kann <code>switch<\/code> dar\u00fcberhinaus auch einen Wert zur\u00fcckgeben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">int<\/span> numLetters = <span class=\"hljs-keyword\">switch<\/span> (day) {\n  <span class=\"hljs-keyword\">case<\/span> MONDAY, FRIDAY, SUNDAY -&gt; <span class=\"hljs-number\">6<\/span>;\n  <span class=\"hljs-keyword\">case<\/span> TUESDAY                -&gt; <span class=\"hljs-number\">7<\/span>;\n  <span class=\"hljs-keyword\">case<\/span> THURSDAY, SATURDAY     -&gt; <span class=\"hljs-number\">8<\/span>;\n  <span class=\"hljs-keyword\">case<\/span> WEDNESDAY              -&gt; <span class=\"hljs-number\">9<\/span>;\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Welche M\u00f6glichkeiten Switch Expressions noch bieten, wie man z. B. aus Code-Bl\u00f6cken mit <code>yield<\/code> einen Wert zur\u00fcckgibt, wann <code>default<\/code>-F\u00e4lle n\u00f6tig sind und wann nicht, und wie der Compiler bei Enums eine Vollst\u00e4ndigkeitsanalyse durchf\u00fchren kann, erf\u00e4hrst du im <a href=\"\/de\/java\/switch-expressions\/\">Hauptartikel \u00fcber Switch Expressions<\/a>.<\/p>\n\n\n\n<p><em>(Erstmals wurden <a href=\"\/de\/java\/java-12-features\/#Switch_Expressions_Preview\">Switch Expressions als Preview-Feature in Java 12<\/a> vorgestellt. <a href=\"\/de\/java\/java-13-features\/#Switch_Expressions_Second_Preview\">Im zweiten Preview in Java 13<\/a> wurde das urspr\u00fcnglich zur R\u00fcckgabe von Werten verwendete Keyword <code>break<\/code> durch <code>yield<\/code> ersetzt. Aufgrund des positiven Feedbacks wurden Switch Expressions in Java 14 mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/361\" target=\"_blank\">JDK Enhancement Proposal 361<\/a> ohne weitere \u00c4nderungen als finales Feature ver\u00f6ffentlicht.)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"helpful-nullpointerexceptions\">Helpful NullPointerExceptions<\/h2>\n\n\n\n<p>Wir kennen alle das folgende Problem: Unser Code wirft eine <code>NullPointerException<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Exception in thread \"main\" java.lang.NullPointerException\n    at eu.happycoders.BusinessLogic.calculate(BusinessLogic.java:80)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Und im Code finden wir dann so etwas:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">long<\/span> value = context.getService().getContainer().getMap().getValue();<\/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>Was ist jetzt <code>null<\/code>? <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>context<\/code>?<\/li>\n\n\n\n<li><code>context.getService()<\/code>?<\/li>\n\n\n\n<li><code>Service.getContainer()<\/code>?<\/li>\n\n\n\n<li><code>Container.getMap()<\/code>?<\/li>\n\n\n\n<li><code>Map.getValue()<\/code>? (falls diese Methode ein <code>Long<\/code>-Objekt zur\u00fcckgibt)<\/li>\n<\/ul>\n\n\n\n<p>Um den Fehler zu beheben, haben wir folgende M\u00f6glichkeiten:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Wir k\u00f6nnten den Quellcode analysieren.<\/li>\n\n\n\n<li>Wir k\u00f6nnten die Applikation debuggen (sehr aufw\u00e4ndig, wenn der Fehler schwer reproduzierbar ist oder nur in Produktion auftritt).<\/li>\n\n\n\n<li>Wir k\u00f6nnten den Code auf mehrere Zeilen aufteilen und erneut ausf\u00fchren (wir m\u00fcssten die Applikation neu deployen und abwarten, bis der Fehler erneut auftritt).<\/li>\n<\/ul>\n\n\n\n<p>Nach einem Upgrade auf Java 14 wirst du dir diese Frage nicht mehr stellen m\u00fcssen, denn dann sieht die Fehlermeldung z. B. so aus:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Exception in thread \"main\" java.lang.NullPointerException: \nCannot invoke \"Map.getValue()\" because the return value of \"Container.getMap()\" is null\n    at eu.happycoders.BusinessLogic.calculate(BusinessLogic.java:80)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Wir k\u00f6nnen nun ganz genau ablesen, an welcher Stelle die Exception aufgetreten ist: <code>Container.getMap()<\/code> lieferte <code>null<\/code> zur\u00fcck, so dass <code>Map.getValue()<\/code> nicht aufgerufen werden konnte.<\/p>\n\n\n\n<p>\u00c4hnliches kann beim Zugriff auf Arrays passieren, wie z. B. in folgender Code-Zeile:<\/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\">this<\/span>.world&#091;x]&#091;y]&#091;z] = value;<\/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>Tritt in dieser Zeile eine <code>NullPointerException<\/code> auf, war bisher nicht erkennbar, ob <code>world<\/code>, <code>world[x]<\/code> oder <code>world[x][y]<\/code> <code>null<\/code> war. Mit Java 14 geht das klar aus der Fehlermeldung hervor:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Exception in thread \"main\" java.lang.NullPointerException: \nCannot store to int array because \"this.world&#091;x]&#091;y]\" is null\n    at eu.happycoders.BusinessLogic.calculate(BusinessLogic.java:107)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In Java 14 sind <em>Helpful NullPointerExceptions<\/em> noch standardm\u00e4\u00dfig deaktiviert und m\u00fcssen mit <code style=\"white-space:nowrap;\">-XX:+ShowCodeDetailsInExceptionMessages<\/code> aktiviert werden. In <a href=\"\/de\/java\/java-15-features\/#Helpful_NullPointerExceptions\">Java 15<\/a> wird das Feature dann von Haus aus aktiviert sein.<\/p>\n\n\n\n<p><em>(Helpful NullPointerExceptions sind in <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/358\" target=\"_blank\">JDK Enhancement Proposal 358<\/a> spezifiziert.)<\/em><\/p>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"experimentelle-preview-und-incubator-features\">Experimentelle, Preview- und Incubator-Features<\/h2>\n\n\n\n<p>Die folgenden Features sind noch nicht produktionsreif. Sie werden in einem mehr oder weniger fortgeschrittenen Entwicklungsstadium mit ausgeliefert, um sie ggf. anhand von Feedback aus der Java-Community noch verbessern zu k\u00f6nnen.<\/p>\n\n\n\n<p>Die ersten drei Features (Records, Pattern Matching for instanceof und Text Blocks) werden (wie Switch Expressions) in <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/amber\/\" target=\"_blank\">Project Amber<\/a> entwickelt, dessen Ziel es ist, die Java-Syntax moderner und pr\u00e4gnanter zu machen.<\/p>\n\n\n\n<p>Ich werde die Features nicht in allen Einzelheiten vorstellen, sondern jeweils nur kurz anrei\u00dfen und auf die Java-Version verweisen, in denen die Features Produktionsreife erlangen. Im entsprechenden Artikel dieser Serie werden sie dann ausf\u00fchrlich behandelt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"records-preview\">Records (Preview)<\/h3>\n\n\n\n<p>Das erste neue Preview-Feature in Java 14 sind Records, definiert in <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/359\" target=\"_blank\">JDK Enhancement Proposal 359<\/a>.<\/p>\n\n\n\n<p>Ein Record bietet eine kompakte Syntax f\u00fcr eine Klasse mit nur finalen Feldern. Diese werden im Konstruktor gesetzt und sind \u00fcber Zugriffsmethoden auslesbar.<\/p>\n\n\n\n<p>Hier ein einfaches 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>Dieser Einzeiler erzeugt eine Klasse <code>Point<\/code> mit<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>finalen Instanzfeldern <code>x<\/code> und <code>y<\/code>, <\/li>\n\n\n\n<li>einem Konstruktor, der beide Felder setzt <\/li>\n\n\n\n<li>und Zugriffsmethoden <code>x()<\/code> und <code>y()<\/code> zum Lesen der Felder. <\/li>\n<\/ul>\n\n\n\n<p><code>Point<\/code> kann wie folgt eingesetzt werden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Point p = <span class=\"hljs-keyword\">new<\/span> Point(<span class=\"hljs-number\">3<\/span>, <span class=\"hljs-number\">5<\/span>);\n<span class=\"hljs-keyword\">int<\/span> x = p.x();\n<span class=\"hljs-keyword\">int<\/span> y = p.y();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Methoden <code>equals()<\/code>, <code>hashCode()<\/code> und <code>toString()<\/code> werden f\u00fcr Records automatisch generiert.<\/p>\n\n\n\n<p>Records k\u00f6nnen um statische Felder und Methoden erweitert werden, nicht aber um Instanzfelder. Sie k\u00f6nnen Interfaces implementieren, aber nicht von anderen Klassen erben. Sie sind implizit final, man kann also auch nicht <em>von<\/em> ihnen erben.<\/p>\n\n\n\n<p>Records werden in <a href=\"\/de\/java\/java-16-features\/\">Java 16<\/a> Produktionsreife erreichen. Eine detaillierte Vorstellung findest du im <a href=\"\/de\/java\/java-records\/\">Hauptartikel \u00fcber Java-Records<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"pattern-matching-for-instanceof-preview\">Pattern Matching for instanceof (Preview)<\/h3>\n\n\n\n<p>Das zweite Preview in Java 14 ist \"Pattern Matching for instanceof\". Dieses Feature, definiert in <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/305\" target=\"_blank\">JDK Enhancement Proposal 305<\/a>, eliminiert die l\u00e4stige Notwendigkeit nach einer <code>instanceof<\/code>-Pr\u00fcfung einen Cast auf den Zieltyp durchzuf\u00fchren.<\/p>\n\n\n\n<p>Am einfachsten l\u00e4sst sich das an einem Beispiel zeigen.<\/p>\n\n\n\n<p>Der folgende Code bekommt das Object <code>obj<\/code> geliefert. Wenn es ein <code>String<\/code> ist und l\u00e4nger als f\u00fcnf Zeichen, soll es in Gro\u00dfbuchstaben umgewandelt und ausgegeben werden. Ist es hingegen ein <code>Integer<\/code>, soll es quadriert und ausgegeben werden.<\/p>\n\n\n\n<p>Dazu m\u00fcssen wir in den Zeilen 4 und 9 jeweils einen Cast durchf\u00fchren.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Object obj = getObject();\n\n<span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String) {\n  String s = (String) obj;\n  <span class=\"hljs-keyword\">if<\/span> (s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n    System.out.println(s.toUpperCase());\n  }\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer) {\n  Integer i = (Integer) obj;\n  System.out.println(i * i);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Viele von uns haben sich so an diese Schreibweise gew\u00f6hnt, dass wir sie gar nicht mehr in Frage stellen. Doch es geht besser!<\/p>\n\n\n\n<p>Ab Java 14 k\u00f6nnen wir die Casts weglassen und den Code stattdessen wie folgt schreiben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s) {\n  <span class=\"hljs-keyword\">if<\/span> (s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n    System.out.println(s.toUpperCase());\n  }\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer i) {\n  System.out.println(i * i);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-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>Hinter einem <code>instanceof<\/code>-Statement k\u00f6nnen wir jetzt einen Variablennamen angeben. Wenn <code>obj<\/code> vom angegebenen Typ ist, wird es an den neuen Variablennamen gebunden; diese neue Variable ist dann vom angegebenen Zieltyp und im \"then-Block\" sichtbar.<\/p>\n\n\n\n<p>Wir k\u00f6nnen sogar noch einen Schritt weitergehen und die <code>if<\/code>-Statements der Zeilen 1 und 2 kombinieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> String s &amp;&amp; s.length() &gt; <span class=\"hljs-number\">5<\/span>) {\n  System.out.println(s.toUpperCase());\n} <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (obj <span class=\"hljs-keyword\">instanceof<\/span> Integer i) {\n  System.out.println(i * i);\n}<\/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>Somit haben wir neun Zeilen Code auf f\u00fcnf Zeilen reduziert und gleichzeitig die Lesbarkeit deutlich erh\u00f6ht.<\/p>\n\n\n\n<p>Genau wie Records wird auch \"Pattern Matching for instanceof\" in <a href=\"\/de\/java\/java-16-features\/#Pattern_Matching_for_instanceof\">Java 16<\/a> production-ready sein.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"text-blocks-second-preview\">Text Blocks (Second Preview)<\/h3>\n\n\n\n<p>Text Blocks wurden in <a href=\"\/de\/java\/java-13-features\/#Text_Blocks_Preview\">Java 13<\/a> als Preview eingef\u00fchrt. Sie erm\u00f6glichen die Notation mehrzeiliger Strings wie in folgendem Beispiel:<\/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\">String sql = <span class=\"hljs-string\">\"\"<\/span><span class=\"hljs-string\">\"\n    SELECT id, firstName, lastName FROM Employee\n    WHERE departmentId = \"<\/span>IT<span class=\"hljs-string\">\"\n    ORDER BY lastName, firstName\"<\/span><span class=\"hljs-string\">\"\"<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/368#New-escape-sequences\" target=\"_blank\">JDK Enhancement Proposal 368<\/a> f\u00fchrt in Java 14 zwei neue Escape-Sequencen ein:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Backslash am Zeilenende, um einen Zeilenumbruch zu unterdr\u00fccken.<\/li>\n\n\n\n<li>\\s f\u00fcr Leerzeichen, um zu verhindern, dass Leerzeichen vom Zeilenende entfernt werden.<\/li>\n<\/ul>\n\n\n\n<p>Beispiele f\u00fcr diese Escape-Sequenzen findest du im <a href=\"\/de\/java\/java-text-blocks\/#Escape-Sequenzen_in_Text_Blocks\">Hauptartikel \u00fcber Text Blocks<\/a>.<\/p>\n\n\n\n<p>Text Blocks werden in der n\u00e4chsten Version, <a href=\"\/de\/java\/java-15-features\/\">Java 15<\/a>, den Produktionsstatus erreichen. Im oben verlinkten Artikel beschreibe ich sie in allen Einzelheiten.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zgc-on-macos-windows-experimental\">ZGC on macOS + Windows (Experimental)<\/h3>\n\n\n\n<p>Der ZGC, ein von Oracle entwickelter Garbage Collector mit dem Ziel Pausezeiten von maximal 10 ms zu erreichen, wurde erstmals <a href=\"\/de\/java\/java-11-features\/#ZGC_A_Scalable_Low-Latency_Garbage_Collector_Experimental\">in Java 11 als experimentelles Feature<\/a> f\u00fcr Linux vorgestellt.<\/p>\n\n\n\n<p>Mit den JDK Enhancement Proposals <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/364\" target=\"_blank\">JEP 364<\/a> und <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/365\" target=\"_blank\">JEP 365<\/a> ist der Z Garbage Collector nun auch unter macOS und Windows verf\u00fcgbar (weiterhin als experimentelles Feature).<\/p>\n\n\n\n<p>Du kannst ZGC mit den JVM-Flags <code>-XX:+UnlockExperimentalVMOptions -XX:+UseZGC<\/code> aktivieren.<\/p>\n\n\n\n<p>ZGC wird in <a href=\"\/de\/java\/java-15-features\/#ZGC_A_Scalable_Low-Latency_Garbage_Collector\">Java 15<\/a> produktionsreif sein. Im entsprechenden Artikel werde ich ihn ausf\u00fchrlich vorstellen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"packaging-tool-incubator\">Packaging Tool (Incubator)<\/h3>\n\n\n\n<p>Basierend auf dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/343\" target=\"_blank\">JDK Enhancement Proposal 343<\/a> wird das Tool <code>jpackage<\/code> entwickelt, mit dem ein plattformspezifischer Installer f\u00fcr eine Java-Anwendung erstellt werden kann, der wiederum die Anwendung und die daf\u00fcr ben\u00f6tigte JRE installiert.<\/p>\n\n\n\n<p>Plattformspezifisch bedeutet dabei, dass sich der Installer f\u00fcr Benutzer einer bestimmten Plattform vertraut anf\u00fchlt. F\u00fcr Windows ist das z. B. eine msi- oder eine exe-Datei, die per Doppelklick gestartet wird. F\u00fcr macOS eine pkg- oder dmg-Datei. Und f\u00fcr Linux eine deb- oder rpm-Datei.<\/p>\n\n\n\n<p>Die Funktionalit\u00e4t soll sich an das Tool <code>javapackager<\/code> anlehnen, das seit JDK 8 mit ausgeliefert wurde, allerdings <a href=\"\/de\/java\/java-11-features\/#JavaFX_geht_eigene_Wege\">in Java 11 mitsamt JavaFX wieder entfernt wurde<\/a>.<\/p>\n\n\n\n<p><code>jpackage<\/code> wird in <a href=\"\/de\/java\/java-16-features\/#Packaging_Tool\">Java 16<\/a> Produktsionsreife erlangen. Im entsprechenden Artikel dieser Serie werde ich zeigen, wie man das Tool einsetzt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"foreign-memory-access-api-incubator\">Foreign-Memory Access API (Incubator)<\/h3>\n\n\n\n<p>Mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/370\" target=\"_blank\">JDK Enhancement Proposal 370<\/a> wird eine API eingef\u00fchrt, die es Java-Programmen erlaubt, effizient und sicher auf Speicher au\u00dferhalb des Java-Heaps zuzugreifen.<\/p>\n\n\n\n<p>Die Foreign-Memory Access API ist ein Teil von <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/panama\/\" target=\"_blank\">Projekt Panama<\/a>, das einen schnelleren und einfacher zu verwendenden  Ersatz f\u00fcr das Java Native Interface (JNI) schaffen soll.<\/p>\n\n\n\n<p>Diese Schnittstelle wird bis Java 18 im Incubator-Status bleiben und in <a href=\"\/de\/java\/java-19-features\/#Foreign_Function_Memory_API_Preview\">Java 19<\/a> als \"Foreign Function &amp; Memory API\" zum ersten Mal als Preview-Version erscheinen.<\/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>In Java 14 gibt es einige Performance-Verbesserungen beim Zugriff auf Speicher und in den Garbage Collectoren.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"non-volatile-mapped-byte-buffers\">Non-Volatile Mapped Byte Buffers<\/h3>\n\n\n\n<p>Mit einem <code>MappedByteBuffer<\/code> kannst du eine Datei in eine Speicherregion \"mappen\", um sie dann \u00fcber regul\u00e4re Speicherzugriffe lesen und beschreiben zu k\u00f6nnen. Mehr dazu findest du im Abschnitt <a href=\"https:\/\/www.happycoders.eu\/de\/java\/filechannel-memory-mapped-io-locks\/#memory-mapped-files-wie-man-einen-teil-einer-datei-in-den-speicher-mappt\">\"Memory-mapped Files\" der Artikelserie \"Dateien in Java\"<\/a>.<\/p>\n\n\n\n<p>Ge\u00e4nderte Daten m\u00fcssen regelm\u00e4\u00dfig in das Speichermedium \u00fcbertragen werden. F\u00fcr NVMs gibt es hierf\u00fcr effizientere Vorgehensweisen mit weniger Overhead als bei herk\u00f6mmlichen Speichermedien.<\/p>\n\n\n\n<p>Ab Java 14 kannst du diese effizienten Mechanismen einsetzen. Dazu musst du beim Erstellen eines <code>MappedByteBuffer<\/code> angeben, dass die Datei auf einem NVM-Medium liegt. Dazu gibst du beim Aufruf von <code>FileChannel.map()<\/code> einen der neuen Modi <code>ExtendedMapMode.READ_ONLY_SYNC<\/code> bzw. <code>ExtendedMapMode.READ_WRITE_SYNC<\/code> an, wie in folgendem Beispiel:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> (FileChannel channel =\n    FileChannel.open(\n        Path.of(<span class=\"hljs-string\">\"test-file.bin\"<\/span>),\n        StandardOpenOption.CREATE,\n        StandardOpenOption.WRITE,\n        StandardOpenOption.READ)) {\n  MappedByteBuffer buffer = channel.map(ExtendedMapMode.READ_WRITE_SYNC, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">256<\/span>);\n  <span class=\"hljs-comment\">\/\/ read from \/ write to the buffer<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Non-Volatile Mapped Byte Buffers sind nur unter Linux verf\u00fcgbar, da nur dort die erforderlichen speziellen Betriebssystem-Aufrufe existieren.<\/p>\n\n\n\n<p><em>(Non-Volatile Byte Buffers sind in <a href=\"https:\/\/openjdk.org:443\/jeps\/352\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 352<\/a> spezifiziert.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"numa-aware-memory-allocation-for-g1\">NUMA-Aware Memory Allocation for G1<\/h3>\n\n\n\n<p>Auf modernen Maschinen mit mehreren CPUs und mehreren Kernen pro CPU spielt die physische Distanz zwischen CPU-Kern und Speichermodul eine immer gr\u00f6\u00dfere Rolle. Je weiter ein Speichermodul vom CPU-Kern entfernt ist, desto h\u00f6her die Latenz beim Speicherzugriff.<\/p>\n\n\n\n<p>Durch den <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/345\" target=\"_blank\">JDK Enhancement Proposal 345<\/a> kann der G1 Garbage Collector ab Java 14 solche Architekturen vorteilhaft nutzen, um die Gesamtperformance zu erh\u00f6hen.<\/p>\n\n\n\n<p>Threads werden naheliegenden NUMA-Knoten zugeordnet. Objekte, die von einem Thread erstellt werden, werden auf immer demselben NUMA-Knoten angelegt. Und solange sie sich in der Young Generation befinden, verbleiben sie auf diesem, indem sie nur in Survivor Regions auf demselben NUMA-Knoten evakuiert werden.<\/p>\n\n\n\n<p>NUMA-Aware Memory Allocation ist nur f\u00fcr Linux verf\u00fcgbar und muss \u00fcber die VM-Option <code>+XX:+UseNUMA<\/code> explizit aktiviert werden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"parallel-gc-verbesserungen\">Parallel GC Verbesserungen<\/h3>\n\n\n\n<p>Im parallelen Garbage Collector wurde das Management f\u00fcr die parallele Abarbeitung von Tasks optimiert, was zu einer deutlichen Leistungsverbesserungen f\u00fchren kann.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecations-und-loeschungen\">Deprecations und L\u00f6schungen<\/h2>\n\n\n\n<p>Die folgenden Funktionen wurden in Java 14 als \"deprecated\" oder \"for removal\" markiert oder endg\u00fcltig aus dem JDK entfernt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"thread-suspend-resume-are-deprecated-for-removal\">Thread Suspend\/Resume Are Deprecated for Removal<\/h3>\n\n\n\n<p>Neben <code>Thread.stop()<\/code> sind auch die folgenden Methoden bereits seit Java 1.2 als \"deprecated\" markiert:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Thread.suspend()<\/code><\/li>\n\n\n\n<li><code>Thread.resume()<\/code><\/li>\n\n\n\n<li><code>ThreadGroup.suspend()<\/code><\/li>\n\n\n\n<li><code>ThreadGroup.resume()<\/code><\/li>\n\n\n\n<li><code>ThreadGroup.allowThreadSuspension()<\/code><\/li>\n<\/ul>\n\n\n\n<p>Der Grund daf\u00fcr ist, dass Thread-Pausierung \u00e4u\u00dferst anf\u00e4llig ist f\u00fcr Deadlocks:<\/p>\n\n\n\n<p>Wenn <code>Thread.suspend()<\/code> innerhalb eines <code>synchronized<\/code>-Blocks aufgerufen wird, bleibt der entsprechende Monitor mindestens solange gesperrt, bis <code>Thread.resume()<\/code> aufgerufen wird. Geschieht dies allerdings in einem anderen Thread, innerhalb eines <code>synchronized<\/code>-Blocks auf demselben Monitor, blockiert dieser zweite Thread beim Versuch den <code>synchronized<\/code>-Block zu betreten.<\/p>\n\n\n\n<p>In Java 14 wurden die o. g. Methoden als \"for removal\" markiert.<\/p>\n\n\n\n<p>Die ebenfalls als \"deprecated\" markierte \u2013 und in meinen Augen viel gef\u00e4hrlichere \u2013 Methode <code>Thread.stop()<\/code> wurde bisher nicht als \"for removal\" markiert und wird uns wohl noch eine Weile begleiten.<\/p>\n\n\n\n<p><em>(F\u00fcr diese \u00c4nderung existiert kein JDK Enhancement Proposal.)<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecate-the-solaris-and-sparc-ports\">Deprecate the Solaris and SPARC Ports<\/h3>\n\n\n\n<p>Das Betriebssystem Solaris und die SPARC-Prozessorarchitektur sind nicht mehr zeitgem\u00e4\u00df. Um Entwicklungsresourcen anderweitig einsetzen zu k\u00f6nnen, hat Oracle im <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/362\" target=\"_blank\">JDK Enhancement Proposal 362<\/a> vorgeschlagen, die Portierungen Solaris\/SPARC, Solaris\/x64 und Linux\/SPARC in Java 14 als \"deprecated\" zu markieren und in einem der n\u00e4chsten Releases komplett zu entfernen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"remove-the-concurrent-mark-sweep-cms-garbage-collector\">Remove the Concurrent Mark Sweep (CMS) Garbage Collector<\/h3>\n\n\n\n<p>Der Concurrent Mark Sweep (CMS) Garbage Collector wurde in Java 9 mit <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/291\" target=\"_blank\">JEP 291<\/a> als \"deprecated\" markiert. Die Entwicklungsressourcen sollten zugunsten modernerer Garbage Collectoren wie G1GC und ZGC umverteilt werden.<\/p>\n\n\n\n<p>Als Ersatz f\u00fcr CMS wird der bereits seit Java 6 verf\u00fcgbare und in Java 9 zum Standard-Garbage-Collector erhobene Allrounder G1 empfohlen.<\/p>\n\n\n\n<p>Mit <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/363\" target=\"_blank\">JEP 363<\/a> wird in Java 14 CMS endg\u00fcltig aus dem JDK entfernt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"deprecate-the-parallelscavenge-serialold-gc-combination\">Deprecate the ParallelScavenge + SerialOld GC Combination<\/h3>\n\n\n\n<p>Es existiert eine ungew\u00f6hnliche und selten genutzte Kombination von GC-Algorithmen: die Paarung aus parallelem GC-Algorithmus f\u00fcr die junge Generation (\"ParallelScavenge\") und seriellem Algorithmus f\u00fcr die alten Generation (\"SerialOld\").<\/p>\n\n\n\n<p>Diese Kombination kann man aktivieren, indem man den ParallelGC aktiviert und gleichzeitig den ParallelOldGC deaktiviert, was wiederum automatisch den SerialOldGC aktiviert:<\/p>\n\n\n\n<p class=\"has-text-align-center\"><code>-XX:+UseParallelGC -XX:-UseParallelOldGC<\/code><\/p>\n\n\n\n<p>So kann man eine Reduzierung des Gesamtspeicherverbrauch von bis zu 3 % des Java-Heaps erzielen.<\/p>\n\n\n\n<p>Dieser Vorteil wiegt jedoch den hohen Wartungsaufwand nicht auf. Daher wurde entschieden, die Entwicklungsresourcen anderweitig einzusetzen und diese GC-Kombination in Java 14 durch <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/366\" target=\"_blank\">JEP 366<\/a> als \"deprecated\" zu markieren. <\/p>\n\n\n\n<p>Als Ersatz wird die Verwendung von parallelem GC sowohl f\u00fcr die junge als auch die alte Generation empfohlen, die wie folgt aktiviert wird: <\/p>\n\n\n\n<p class=\"has-text-align-center\"><code>-XX:+UseParallelGC<\/code><\/p>\n\n\n\n<p>Bereits in Java 15 wird die Kombination ParallelScavenge + SerialOld nicht mehr verwendbar sein. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"remove-the-pack200-tools-and-api\">Remove the Pack200 Tools and API<\/h3>\n\n\n\n<p>Das in Java 5 eingef\u00fchrte Kompressionsverfahren f\u00fcr .class- und .jar-Dateien, <a href=\"\/de\/java\/java-11-features\/#Deprecate_the_Pack200_Tools_and_API\">Pack200 wurde in Java 11 als \"deprecated\" markiert<\/a>.<\/p>\n\n\n\n<p>Der Aufwand um solch spezielle Kompressionsverfahren zu maintainen \u2013 nur um gegen\u00fcber Standardverfahren ein paar zus\u00e4tzliche Bytes herauszukitzeln \u2013 steht in Zeiten von 100-MBit-DSL-Leitungen und 18-TB-Festplatten in keinem Verh\u00e4ltnis mehr zum Nutzen.<\/p>\n\n\n\n<p>Mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/367\" target=\"_blank\">JDK Enhancement Proposal 367<\/a> wurden Pack200 und die zugeh\u00f6rigen Tools jetzt endg\u00fcltig aus dem JDK entfernt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"sonstige-aenderungen-in-java-14\">Sonstige \u00c4nderungen in Java 14<\/h2>\n\n\n\n<p>Habe ich in dieser Kategorie bisher immer \u00c4nderungen aufgelistet, die man als Java-Entwicklerin und -Entwickler nicht unbedingt kennen musste, sind in Java 14 auch die \"Sonstigen \u00c4nderungen\" durchaus interessant.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"jfr-event-streaming\">JFR Event Streaming<\/h3>\n\n\n\n<p>Im Artikel \u00fcber <a rel=\"noopener\" href=\"\/de\/java\/java-11-features\/#Java_Flight_Recorder\" target=\"_blank\">Java 11 habe ich Java Flight Recorder (JFR)<\/a> und JDK Mission Control (JMC) vorgestellt. Flight Recorder sammelt w\u00e4hrend der Ausf\u00fchrung einer Anwendung wertvolle Daten \u00fcber die JVM und speichert sie in einer Datei. Die gespeicherten Daten k\u00f6nnen dann mit Mission Control visualisiert werden:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full_800\"><img decoding=\"async\" width=\"800\" height=\"554\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-800x554.png\" alt=\"JDK Mission Control\" class=\"wp-image-23531\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-800x554.png 800w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-224x155.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-336x233.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-504x349.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-672x465.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-400x277.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-600x416.png 600w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-944x654.png 944w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01-1200x831.png 1200w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/10\/JDK-Mission-Control-01.png 1600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">JDK Mission Control<\/figcaption><\/figure>\n<\/div>\n\n\n<p><a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/349\" target=\"_blank\">JDK Enhancement Proposal 349<\/a> erm\u00f6glicht ab Java 14 auch eine kontinuierliche \u00dcberwachung einer Java-Anwendung, indem die von Flight Recorder gesammelten Daten aus der laufenden Anwendung heraus ausgelesen werden k\u00f6nnen (anstatt sie in einer Datei zu speichern und im Nachhinein zu analyiseren).<\/p>\n\n\n\n<p>Wie das funktioniert, zeigt folgender Beispiel-Quellcode:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">int<\/span>&#091;] array = createRandomArray(<span class=\"hljs-number\">1_000_000_000<\/span>);\n\n<span class=\"hljs-keyword\">try<\/span> (<span class=\"hljs-keyword\">var<\/span> rs = <span class=\"hljs-keyword\">new<\/span> RecordingStream()) {\n  rs.enable(<span class=\"hljs-string\">\"jdk.CPULoad\"<\/span>).withPeriod(Duration.ofSeconds(<span class=\"hljs-number\">1<\/span>));\n\n  rs.onEvent(\n      <span class=\"hljs-string\">\"jdk.CPULoad\"<\/span>,\n      event -&gt; {\n        <span class=\"hljs-keyword\">float<\/span> jvmUser = event.getFloat(<span class=\"hljs-string\">\"jvmUser\"<\/span>);\n        <span class=\"hljs-keyword\">float<\/span> jvmSystem = event.getFloat(<span class=\"hljs-string\">\"jvmSystem\"<\/span>);\n        <span class=\"hljs-keyword\">float<\/span> machineTotal = event.getFloat(<span class=\"hljs-string\">\"machineTotal\"<\/span>);\n\n        System.out.printf(\n            Locale.US,\n            <span class=\"hljs-string\">\"JVM User: %5.1f %%, JVM System: %5.1f %%, Machine Total: %5.1f %%%n\"<\/span>,\n            jvmUser * <span class=\"hljs-number\">100<\/span>,\n            jvmSystem * <span class=\"hljs-number\">100<\/span>,\n            machineTotal * <span class=\"hljs-number\">100<\/span>);\n      });\n\n  rs.startAsync();\n\n  Arrays.parallelSort(array);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Zun\u00e4chst wird mit <code>new RecordingStream()<\/code> ein Stream von JFR-Events erzeugt.<\/p>\n\n\n\n<p>Mit <code>RecordingStream.enable()<\/code> wird ein konkretes Event (im Beispiel \"jdk.CPULoad\" aktiviert).<\/p>\n\n\n\n<p>Mit <code>RecordingStream.onEvent()<\/code> definieren wir, wie auf das Event reagiert werden soll. Das Event selbst besteht aus mehreren Datenfelder, die wir mit <code>getFloat()<\/code> oder \u2013 je nach Datentyp \u2013 anderen Gettern auslesen k\u00f6nnen.<\/p>\n\n\n\n<p>Mit <code>RecordingStream.startAsync()<\/code> starten wir die Aufzeichnung in einem separaten Thread. Im Hauptthread sortieren wir ein Array mit einer Milliarde Elemente, was auf meinem Laptop etwa 15 Sekunden dauert.<\/p>\n\n\n\n<p>W\u00e4hrenddessen sieht man anhand der Flight-Recorder-Daten gut, dass <code>Arrays.parallelSort()<\/code> die CPU nahezu vollst\u00e4ndig auslastet:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">JVM User:  45.1 %, JVM System:  15.0 %, Machine Total:  60.1 %\nJVM User:  86.5 %, JVM System:   0.5 %, Machine Total:  95.2 %\nJVM User:  91.8 %, JVM System:   0.3 %, Machine Total: 100.0 %\nJVM User:  93.0 %, JVM System:   0.2 %, Machine Total:  96.9 %\n...<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"accounting-currency-format-support\">Accounting Currency Format Support<\/h3>\n\n\n\n<p>In manchen L\u00e4ndern, z. B. in den USA, werden negative Zahlen in der Buchhaltung nicht mit einem Minuszeichen gekennzeichnet, sondern durch runde Klammern.<\/p>\n\n\n\n<p>In Java 14 wird die sogenannte Language-Tag Extension \"u-cf-account\" hinzugef\u00fcgt, die es erm\u00f6glicht, in einem <code>Locale<\/code>-Objekt die Zusatzinformation anzugeben, ob dieses im Kontext der Buchhaltung verwendet wird.<\/p>\n\n\n\n<p>Du kannst diese Extension wie in folgendem Beispiel einsetzen:<\/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-comment\">\/\/ Example *without* language tag extension<\/span>\nLocale locale = Locale.forLanguageTag(<span class=\"hljs-string\">\"en-US\"<\/span>);\nNumberFormat cf = NumberFormat.getCurrencyInstance(locale);\nSystem.out.println(<span class=\"hljs-string\">\"Normal:     \"<\/span> + cf.format(-<span class=\"hljs-number\">14.95<\/span>));\n\n<span class=\"hljs-comment\">\/\/ Example *with* language tag extension<\/span>\nLocale localeAccounting = Locale.forLanguageTag(<span class=\"hljs-string\">\"en-US-u-cf-account\"<\/span>);\nNumberFormat cfAccounting = NumberFormat.getCurrencyInstance(localeAccounting);\nSystem.out.println(<span class=\"hljs-string\">\"Accounting: \"<\/span> + cfAccounting.format(-<span class=\"hljs-number\">14.95<\/span>));<\/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>Ab Java 14 gibt das Programm folgendes aus:<\/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\">Normal:     -$14.95\nAccounting: ($14.95)<\/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>Wenn du das Programm unter Java 13 oder \u00e4lter laufen l\u00e4sst, wird die Tag Extension ignoriert, und das Programm formatiert beide Male gleich:<\/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\">Normal:     -$14.95\nAccounting: -$14.95<\/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>Weitere <a href=\"\/de\/java\/java-10-features\/#Additional_Unicode_Language-Tag_Extensions\">Unicode Language-Tag Extensions findest du im Artikel \u00fcber Java 10<\/a>. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vollstaendige-liste-aller-aenderungen-in-java-14\">Vollst\u00e4ndige Liste aller \u00c4nderungen in Java 14<\/h3>\n\n\n\n<p>Dieser Artikel hat alle Features von Java 14 vorgestellt, die in JDK Enhancement Proposals definiert sind, sowie einige Performance-Verbesserungen und L\u00f6schungen, die keinem JEP zugeordnet sind.<\/p>\n\n\n\n<p>Eine vollst\u00e4ndige Liste aller \u00c4nderungen findest du in den&nbsp;<a rel=\"noopener\" href=\"https:\/\/www.oracle.com\/java\/technologies\/javase\/14-relnote-issues.html\" target=\"_blank\">offiziellen Java 14 Release Notes<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"fazit\">Fazit<\/h2>\n\n\n\n<p>Java 14 ist ein eindrucksvolles Release. Switch Expressions sind produktionsreif. Und dank \"Helpful NullPointerExceptions\" sparen wir uns in Zukunft eine Menge Debugging-Arbeit.<\/p>\n\n\n\n<p>Mit Records und \"Pattern Matching for instanceof\" wurden zwei weitere Features aus <a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/projects\/amber\/\" target=\"_blank\">Project Amber<\/a> als Preview ins JDK \u00fcbernommen. Text Blocks wurden um die Escape-Sequenzen \"Backslash am Zeilenende\" und \"\\s\" erweitert.<\/p>\n\n\n\n<p>Der (noch experimentelle) Low-Latency Garbage Collector ZGC ist nun auch unter Windows und macOS verf\u00fcgbar. Und wer seit Java 11 den <code>javapackager<\/code> vermisst, kann ab Java 14 mit dessen Nachfolger <code>jpackage<\/code> experimentieren.<\/p>\n\n\n\n<p>JFR Event Streaming und mehrere Performance-Verbesserungen runden das Release ab.<\/p>\n\n\n\n<p>Wenn dir der Artikel gefallen hat, hinterlasse mir gerne einen Kommentar oder teile den Artikel \u00fcber einen der Share-Buttons am Ende.<\/p>\n\n\n\n<p>Und wenn du informiert werden m\u00f6chtest, wenn der n\u00e4chste Artikel online geht, dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den kostenlosen HappyCoders-Newsletter anzumelden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Alle neuen Features von Java 14: Switch Expressions, Helpful NullPointerExceptions, Previews: Records + Pattern matching for instanceof + mehr...<\/p>\n","protected":false},"author":1,"featured_media":34270,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"none","_seopress_titles_title":"","_seopress_titles_desc":"Java 14 Features mit Beispielen: Switch Expressions, Helpful NullPointerExceptions, Previews: Records + Pattern matching for instanceof + mehr.","_seopress_robots_index":"","_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":22580,"_post_count":0,"footnotes":""},"categories":[64],"tags":[176],"class_list":["post-24048","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\/11\/java-14-features.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-features.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2021\/11\/java-14-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 14: Switch Expressions, Helpful NullPointerExceptions, Previews: Records + Pattern matching for instanceof + mehr...","public_identification_id":"3af3535744eb4f6a8893b6ab5c7c90db","private_identification_id":"05b032f552254de98b14a5ff6fe64064","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/24048","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=24048"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/24048\/revisions"}],"predecessor-version":[{"id":39765,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/24048\/revisions\/39765"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34270"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=24048"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=24048"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=24048"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}