{"id":4680,"date":"2023-08-26T10:41:55","date_gmt":"2023-08-26T08:41:55","guid":{"rendered":"https:\/\/www.tutego.de\/blog\/javainsel\/?p=4680"},"modified":"2023-08-26T10:41:55","modified_gmt":"2023-08-26T08:41:55","slug":"pattern-matching-bei-switch-in-java-21","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2023\/08\/pattern-matching-bei-switch-in-java-21\/","title":{"rendered":"Inselupdate: Pattern-Matching bei switch in Java 21"},"content":{"rendered":"<p>Wir haben bereits gesehen, dass der instanceof-Operator genutzt werden kann, um einen einzelnen Typ zu pr\u00fcfen. Nun k\u00f6nnen wir diese Fallunterscheidung erweitern, um mehrere Typen zu testen. Nehmen wir an, dass die Zust\u00e4nde von Nap, Workout und Event im XML-Format gespeichert werden sollen. In diesem Kontext kann eine neue Methode die Abbildung auf XML \u00fcbernehmen:<\/p>\n<pre>static String toXml( Object o ) {\r\n\r\n\u00a0 if ( o == null )\r\n\r\n\u00a0\u00a0\u00a0 return \"&lt;null \/&gt;\";\r\n\r\n\u00a0 <strong>if ( o instanceof Nap nap )<\/strong>\r\n\r\n\u00a0\u00a0\u00a0 return \"&lt;nap about=\\\"%s\\\" duration=%s \/&gt;\".formatted( nap.about, nap.duration );\r\n\r\n\u00a0 <strong>else if ( o instanceof Workout workout )<\/strong>\r\n\r\n\u00a0\u00a0\u00a0 return \"&lt;workout about=\\\"%s\\\" duration=%s caloriesBurned=%s\/&gt; \"\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .formatted( workout.about, workout.duration,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 workout.caloriesBurned );\r\n\r\n\u00a0 e<strong>lse if ( o instanceof Event event )<\/strong>\r\n\r\n\u00a0\u00a0\u00a0 return \"&lt;event about=\\\"%s\\\" duration=%s \/&gt;\".formatted( event.about, event.duration );\r\n\r\n\u00a0 else\r\n\r\n\u00a0\u00a0\u00a0 return \"&lt;object \/&gt;\";\r\n\r\n}<\/pre>\n<p>Gerade f\u00fcr solche Abfragen wurde in Java 21 die switch-Anweisung bzw. der switch-Ausdruck erweitert, um die M\u00f6glichkeit zu bieten, Typen zu testen und somit eine kaskadierte Typpr\u00fcfung durchzuf\u00fchren. Diese Erweiterung wird als Pattern-Matching bei switch (engl. Pattern Matching for switch)<a href=\"#_ftn1\" name=\"_ftnref1\">[1]<\/a> bezeichnet, und es handelt sich um das Pendant zum Pattern-Matching bei instanceof.<\/p>\n<p>Die Methode toXml(\u2026) kann folgenderma\u00dfen umgeschrieben werden:<\/p>\n<pre>static String toXml( Object o ) {\r\n\r\n\u00a0 switch ( o ) {\r\n\r\n\u00a0\u00a0\u00a0 <strong>case null<\/strong> -&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return \"&lt;null \/&gt;\";\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 <strong>case Nap nap<\/strong> -&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return \"&lt;nap about=\\\"%s\\\" duration=%s \/&gt;\".formatted( nap.about, nap.duration );\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 <strong>case Workout workout<\/strong> -&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return \"&lt;workout about=\\\"%s\\\" duration=%s caloriesBurned=%s\/&gt; \"\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .formatted( workout.about, workout.duration,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0workout.caloriesBurned );\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 <strong>case Event event<\/strong> -&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return \"&lt;event about=\\\"%s\\\" duration=%s \/&gt;\".formatted( event.about, event.duration );\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 <strong>default<\/strong> -&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return \"&lt;object \/&gt;\";\r\n\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0 }\r\n\r\n}<\/pre>\n<p>Die \u00dcberpr\u00fcfung auf null ist mithilfe von case null m\u00f6glich \u2013 eine weitere Erweiterung von Java 21.<\/p>\n<p><strong>Hinweis:\u00a0<\/strong>Auch in F\u00e4llen, in denen eine switch-Anweisung verwendet wird, muss beim Pattern-Matching die Abdeckung vollst\u00e4ndig sein. Daher ist in unserem Fall der default-Zweig erforderlich.<\/p>\n<p>Die gew\u00e4hlte L\u00f6sung mit der switch-Anweisung ist zwar umsetzbar, doch da jeder switch-Block mit einem return endet, ist auch ein switch-Ausdruck m\u00f6glich. Eine alternative Schreibeweise f\u00fcr toXml(\u2026) lautet:<\/p>\n<pre>static String toXml( Object o ) {\r\n\r\n\u00a0 return switch ( o ) {\r\n\r\n\u00a0\u00a0\u00a0 <strong>case null<\/strong> -&gt; \"&lt;null \/&gt;\";\r\n\r\n\u00a0\u00a0\u00a0 <strong>case Nap nap<\/strong> -&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"&lt;nap about=\\\"%s\\\" duration=%s \/&gt;\".formatted( nap.about, nap.duration );\r\n\r\n\u00a0\u00a0\u00a0 <strong>case Workout workout<\/strong> -&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"&lt;workout about=\\\"%s\\\" duration=%s caloriesBurned=%s\/&gt; \"\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0.formatted( workout.about, workout.duration,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0workout.caloriesBurned );\r\n\r\n\u00a0\u00a0\u00a0 <strong>case Event event<\/strong> -&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"&lt;event about=\\\"%s\\\" duration=%s \/&gt;\".formatted( event.about, event.duration );\r\n\r\n\u00a0\u00a0\u00a0 default -&gt; \"&lt;object \/&gt;\";\r\n\r\n\u00a0 };\r\n\r\n}<\/pre>\n<p>Dominanz<\/p>\n<p>Normalerweise spielt bei einem switch-case die Reihenfolge der case-Bl\u00f6cke keine Rolle \u2013abgesehen vom Durchfallen, was jedoch bei -&gt; nicht mehr existiert. Beim Pattern-Matching spielt die Reihenfolge sehr wohl eine Rolle und folgendes w\u00e4re <em>nicht<\/em> korrekt:<\/p>\n<pre>return switch ( o ) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\r\n\u00a0 case null -&gt; \"&lt;null \/&gt;\";\r\n\r\n\u00a0 <strong>case Event event<\/strong> -&gt; \"\u2026\";\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\/\/ \u2620 case-Label dominiert\r\n\r\n\u00a0 <strong>case Nap nap<\/strong> -&gt; \"\u2026\";\r\n\r\n\u00a0 \u2026\r\n\r\n}<\/pre>\n<p>Das case-Label case Event event dominiert das case-Label case Nap nap, daher m\u00fcssen wir die Reihenfolge ber\u00fccksichtigen. Im \u00dcbrigen gibt es bei der Ausnahmebehandlung einen \u00e4hnlichen Fall, Details finden meine Leser im Abschnitt 9.3.5, \u201eSchon gefangen?\u201c<\/p>\n<h4>Pattern-Matching mit when W\u00e4chter<\/h4>\n<p>Bisher haben wir in den case-Blocken nur den Typ \u00fcberpr\u00fcft. Es ist jedoch m\u00f6glich, zus\u00e4tzliche Bedingungen anzuf\u00fcgen. Hierf\u00fcr wird nach der Pattern-Variable das Schl\u00fcsselwort when verwendet, gefolgt von einer Bedingung, die auf die Pattern-Variable:<\/p>\n<pre>Event event = new Nap();\r\n\r\nswitch ( event ) {\r\n\r\n\u00a0 case Nap nap\r\n\r\n\u00a0 <strong>when nap.duration &lt; 10<\/strong> -&gt;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 System.out.println( \"Too brief a sleep, not worth it.\" );\r\n\r\n\r\n\r\n\r\n\u00a0 case Nap nap\r\n\r\n\u00a0 <strong>when nap.duration &gt; 100<\/strong> -&gt; System.out.println( \"That's too long, wake up.\" );\r\n\r\n<strong>\u00a0<\/strong>\r\n\r\n\u00a0 case Nap nap -&gt; System.out.println( \"Recharge and renew with every sleep\" );\r\n\r\n\r\n\r\n\r\n\u00a0 case Workout workout -&gt; System.out.println( \"Elevate your fitness game\");\r\n\r\n\r\n\r\n\r\n\u00a0 default -&gt; {}\r\n\r\n}<\/pre>\n<p>Hinter dem Schl\u00fcsselwort when kann eine Bedingung angegeben werden, die als W\u00e4chter (engl. <em>guard<\/em>) bezeichnet wird. Die Auswertung des case-Blocks erfolgt erst, wenn der Typ \u00fcbereinstimmt und die Bedingung erf\u00fcllt ist. Die Pr\u00fcfung auf den gleichen Typ kann mehrfach in verschiedenen Bl\u00f6cken erfolgen. Wir m\u00fcssen auch hier wieder die Dominanz ber\u00fccksichtigen. So w\u00e4re es falsch, mit case Nap nap -&gt; zu beginnen und erst dahinter ein case Nap nap when \u2026 -&gt; zu setzen.<\/p>\n<p><a href=\"#_ftnref1\" name=\"_ftn1\">[1]<\/a> https:\/\/openjdk.org\/jeps\/433<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wir haben bereits gesehen, dass der instanceof-Operator genutzt werden kann, um einen einzelnen Typ zu pr\u00fcfen. Nun k\u00f6nnen wir diese Fallunterscheidung erweitern, um mehrere Typen zu testen. Nehmen wir an, dass die Zust\u00e4nde von Nap, Workout und Event im XML-Format gespeichert werden sollen. In diesem Kontext kann eine neue Methode die Abbildung auf XML \u00fcbernehmen: [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[11,124],"tags":[],"class_list":["post-4680","post","type-post","status-publish","format-standard","hentry","category-insel","category-java-21"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4680","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=4680"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4680\/revisions"}],"predecessor-version":[{"id":4681,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4680\/revisions\/4681"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=4680"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=4680"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=4680"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}