{"id":176262,"date":"2021-09-06T17:38:03","date_gmt":"2021-09-06T16:38:03","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=176262"},"modified":"2025-09-19T15:38:09","modified_gmt":"2025-09-19T14:38:09","slug":"java-17-and-intellij-idea","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/en\/idea\/2021\/09\/java-17-and-intellij-idea","title":{"rendered":"Java 17 and IntelliJ IDEA"},"content":{"rendered":"\n<p>A new Java release every six months can be exciting, overwhelming, or both. Given that <a href=\"https:\/\/openjdk.java.net\/projects\/jdk\/17\/\" target=\"_blank\" rel=\"noopener\">Java 17<\/a> is also an <a href=\"https:\/\/www.oracle.com\/java\/technologies\/java-se-support-roadmap.html\" class=\"ek-link\" target=\"_blank\" rel=\"noopener\">LTS<\/a> release, it\u2019s not just the developers but enterprises also noticing it. If you have been <a href=\"https:\/\/www.ted.com\/talks\/tim_urban_inside_the_mind_of_a_master_procrastinator\" target=\"_blank\" rel=\"noopener\">waiting<\/a> to move on from Java 8 or 11, now is the time to weigh its advantages.<\/p>\n\n\n\n<p>In this blog post, I will limit the coverage of Java 17 to its language features \u2013 <a href=\"https:\/\/openjdk.java.net\/jeps\/409\" class=\"ek-link\" target=\"_blank\" rel=\"noopener\">Sealed Classes<\/a> and <a href=\"https:\/\/openjdk.java.net\/jeps\/406\" class=\"ek-link\" target=\"_blank\" rel=\"noopener\">Pattern Matching for switch<\/a>. I\u2019ll cover what these features are, why you might need them, and how you can start using them in <a href=\"https:\/\/blog.jetbrains.com\/idea\/2021\/08\/intellij-idea-2021-2-1\/\" class=\"ek-link\">IntelliJ IDEA<\/a>. I will also highlight how these features can reduce the <em>cognitive complexity<\/em> for developers. You can use <a href=\"https:\/\/openjdk.java.net\/projects\/jdk\/17\/\" target=\"_blank\" rel=\"noopener\">this link<\/a> for a comprehensive list of all the new Java 17 features.&nbsp;<\/p>\n\n\n\n<p>Added as a standard Java language feature in Java 17, sealed classes enable you to <em>control<\/em> the hierarchies to model your business domain. Sealed classes decouple accessibility from extensibility. Now a visible class or interface doesn&#8217;t need to be implicitly extensible.<\/p>\n\n\n\n<p>Pattern matching for switch is introduced as a <a href=\"https:\/\/openjdk.java.net\/jeps\/12\" target=\"_blank\" rel=\"noopener\">preview feature<\/a>. As the name suggests, it adds patterns to the case labels in the switch statements <em>and<\/em> switch expressions. The type of the <em>selector expression<\/em> that can be used with a switch is expanded to any reference value. Also, case labels are no longer limited to constant values. It also helps replace if-else statement chains with switch, improving code readability.<\/p>\n\n\n\n<p>Let\u2019s start with pattern matching.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/Java17_blog_Blog_1280x720.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Before we dive into pattern matching for switch, let\u2019s ensure we have the basic IntelliJ IDEA configuration set up.<\/p>\n\n\n\n<p><strong>IntelliJ IDEA Configuration<\/strong><\/p>\n\n\n\n<p>Basic support for Java 17 is available in <a href=\"https:\/\/blog.jetbrains.com\/idea\/2021\/08\/intellij-idea-2021-2-1\/\" class=\"ek-link\">IntelliJ IDEA 2021.2.1<\/a>. More support is on the way in future IntelliJ IDEA releases.&nbsp;<\/p>\n\n\n\n<p>To use pattern matching for switch with Java 17, go to <em>ProjectSettings | Project<\/em>, set the <em>Project SDK<\/em> to 17 and set <em>Project language level<\/em> to \u2018<em>17 (Preview) &#8211; Pattern matching for switch<\/em>\u2019:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1526\" height=\"993\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-img1.png\" alt=\"\" class=\"wp-image-178620\"\/><\/figure>\n\n\n\n<p>You can use any version of the JDK that has already been downloaded on your system, or download another version by clicking on \u2018<em>Edit<\/em>\u2019 and then selecting \u2018<em>Add SDK &gt;<\/em>\u2019, followed by \u2018<em>Download JDK\u2026<\/em>\u2019. You can choose the JDK version to download from a list of vendors.<\/p>\n\n\n\n<p>On the Modules tab, ensure the same language level is selected for the modules &#8211; <em>17 (Preview) &#8211; Pattern matching for switch<\/em>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1522\" height=\"536\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-img2.png\" alt=\"\" class=\"wp-image-178631\"\/><\/figure>\n\n\n\n<p>Once you select this, you might see the following pop-up which informs you that IntelliJ IDEA might discontinue the support for the Java preview language features in its next versions. Since a preview feature is not permanent (yet), and it is possible that it could change (or even be dropped) in a future Java release. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"643\" height=\"246\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-img3.png\" alt=\"\" class=\"wp-image-178642\"\/><\/figure>\n\n\n\n<p>Ok, now we are ready to start with the Java 17 language features.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\"><strong>Pattern matching for switch (a preview feature)<\/strong><\/h1>\n\n\n\n<p>Pattern matching is a big topic and it is being rolled out in batches in the Java language. It started with <a href=\"https:\/\/openjdk.java.net\/jeps\/394\" target=\"_blank\" rel=\"noopener\">pattern matching for instanceof<\/a> (previewed in Java 14, and becoming a standard feature in Java 16). Pattern matching for switch is included in Java 17, and we are already looking at deconstructing records and arrays with <a href=\"https:\/\/openjdk.java.net\/jeps\/405\" target=\"_blank\" rel=\"noopener\">record patterns and array patterns<\/a> in Java 18.&nbsp;<\/p>\n\n\n\n<p>To understand pattern matching for switch, it will be beneficial to have an understanding of:<\/p>\n\n\n\n<ol>\n<li>Pattern matching, in general<\/li>\n\n\n\n<li>Pattern matching for instanceof&nbsp;<\/li>\n\n\n\n<li>The enhancement of switch construct with <a href=\"https:\/\/openjdk.java.net\/jeps\/361\" target=\"_blank\" rel=\"noopener\">Switch Expressions<\/a>&nbsp;<\/li>\n<\/ol>\n\n\n\n<p>If you are already familiar with all of the preceding topics, feel free to skip to the section &#8216;Welcome to pattern matching for switch&#8217;.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What is pattern matching?<\/strong><\/h2>\n\n\n\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Pattern_matching\" target=\"_blank\" rel=\"noopener\">Wikipedia<\/a> states pattern matching is \u201cthe act of checking a given sequence of tokens for the presence of the constituents of some pattern\u201d.&nbsp;<\/p>\n\n\n\n<p>Let\u2019s make it more specific to our examples. You can compare pattern matching to a test \u2013 a test that should be passed by a value (primitive or object) against a condition. For example, the following are valid pattern matching examples:<\/p>\n\n\n\n<ol>\n<li>Is the value an instance of class <code>String<\/code>?<\/li>\n\n\n\n<li>Is the value a subclass of class <code>AirPollution<\/code>, and the value returned by one of its methods, say, <code>getAQI()<\/code> is &gt; 200?<\/li>\n<\/ol>\n\n\n\n<p>There are different types of patterns. In this blog post, I\u2019ll cover type patterns, guarded patterns, and parenthesised patterns \u2013 since they are relevant to pattern matching for switch.<\/p>\n\n\n\n<p>Pattern matching for instanceof uses type pattern. Let\u2019s look at how it works.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Pattern matching for instanceof<\/strong><\/h2>\n\n\n\n<p>This feature extends the <code>instanceof<\/code> operator with the possibility to use a type pattern. It checks whether an instance is of a certain type. If the test passes, it casts and assigns the value to a pattern variable. This removes the need to define an additional variable or to perform explicit casting in order to to use members of the instance being compared.<\/p>\n\n\n\n<p>Here\u2019s an example of code that can be commonly found in codebases (which doesn\u2019t use patterns matching for instanceof):<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">void outputValueInUppercase(Object obj) {\n   if (obj instanceof String) {              \n       String s = (String) obj;             \n       System.out.println(s.toUpperCase()); \n   }\n}<\/pre>\n\n\n\n<p>In IntelliJ IDEA, you can invoke context-sensitive actions on the variable s (by using Alt+Enter or by clicking the light bulb icon) and selecting <em>Replace \u2018s\u2019 with pattern variable<\/em> to use pattern matching for instanceof:<\/p>\n\n\n\n<figure class=\"wp-block-image alignnone wp-image-16062\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-1.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>The scope of the pattern variable (a local variable) is limited to the <code>if<\/code>-block because it makes no sense to be able to access the pattern variable if the test fails.<\/p>\n\n\n\n<p>The simplicity of pattern matching of instanceof might be deceptive. If you are thinking it doesn\u2019t matter much since it only removes one line of code, think again. Removal of just one line of code can open up a number of possibilities in which you can modify your code. For example, aside from using pattern matching for instanceof, the following code merges <code>if<\/code> statements, introduces a pattern variable, and replaces a for loop with <code>Collection.removeIf()<\/code>:<\/p>\n\n\n\n<figure class=\"wp-block-image alignnone wp-image-16062\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-2.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>Now, let me brief you on the enhancements to the switch statement with the switch expressions (covered in detail <a href=\"https:\/\/blog.jetbrains.com\/idea\/2019\/02\/java-12-and-intellij-idea\">here<\/a>, with Java 12, and <a href=\"https:\/\/blog.jetbrains.com\/idea\/2019\/11\/java-13-and-intellij-idea\/\">here<\/a> with changes in Java 13). As I mentioned before, if you are already familiar with switch expressions, please feel free to jump to the section &#8216;Welcome to pattern matching for switch&#8217;.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Switch expressions \u2013 what benefits do they bring to the table?<\/strong><\/h3>\n\n\n\n<p>Switch expressions enhance the switch statement and improve the coding experience for developers. As compared to the switch statements, switch expressions can <em>return a value<\/em>. The ability to define <em>multiple constants with a switch branch<\/em>, and the improved code semantics, makes it <em>concise<\/em>. By removing default fall-through in the switch branches, you are less likely to introduce a <em>logical error<\/em> in a switch expression.&nbsp;<\/p>\n\n\n\n<p>Let&#8217;s look at an example that demonstrates the advantages switch expressions can have over switch statements.<\/p>\n\n\n\n<p>In the following code, the switch statement has repetitive break and assignment statements in case labels, which adds noise to the code. The default fall-through in switch branches can sneak in a logical error. For example, if we delete the break statement for case label <code>STRAW<\/code>, it results in an assignment of 300 instead of 200 to the variable <code>damage<\/code> when you call the method&nbsp; <code>getDamageToPlanet()<\/code>, passing it the value <code>SingleUsePlastic.STRAW<\/code>. Also, with switch statements there isn\u2019t any way to exhaustively iterate over the finite enum values:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class Planet {\n\n    enum SingleUsePlastic {\n        CUP, STRAW, BOTTLE\n    }\n\n    int getDamageToPlanet(SingleUsePlastic plastic) {\n        int damage = -1;\n        switch (plastic) {\n            case CUP:\n                damage = 100;\n                break;\n            case STRAW:\n                damage = 200;\n                break;\n            case BOTTLE:\n                damage = 300;\n                break;\n        }\n        return damage;\n    }\n}<\/pre>\n\n\n\n<p>Let\u2019s see how switch expressions can help. The following gif demonstrates some of the benefits of switch expressions such as concise code, improved code semantics, no redundant break statements, exhaustive iteration, and more:<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-16062\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-3.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>With a basic understanding of pattern matching, pattern matching for instanceof, and switch expressions, let\u2019s look at what pattern matching is and why you need it?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Welcome to Pattern matching for switch<\/strong><\/h2>\n\n\n\n<p>Imagine being able to replace long if-else statement chains with concise switch statements <em>or<\/em> expressions. Yes, you read that correctly. Pattern matching for switch applies to both switch statements and switch expressions.&nbsp;<\/p>\n\n\n\n<p>If you are wondering about the limited types of selector expressions (integral primitives, namely <code>byte<\/code>, <code>short<\/code>, <code>char<\/code>, <code>int<\/code>, their corresponding wrapper classes, <code>String<\/code> and enum) that could be earlier passed to switch, don\u2019t worry. With pattern matching for switch, type of selector expression for a switch statement and switch expression has been increased to <em>any reference value <\/em>and integral primitive values (<code>byte<\/code>, <code>short<\/code>, <code>char<\/code>, and <code>int<\/code>).&nbsp;<\/p>\n\n\n\n<p>Also, the case labels are no longer restricted to constants. They can define patterns \u2013 like type patterns, guarded patterns, and parenthesized patterns. <\/p>\n\n\n\n<p>Let\u2019s start with an example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Replace if-else statement chains with concise switch constructs \u2013 that test types beyond int integrals, String, or enums.<\/strong><\/h3>\n\n\n\n<p>You can work with switch constructs that can be passed a wide range of selector expressions, and can test values not just against constants but also types. That\u2019s not all, case labels can also include complex conditions.<\/p>\n\n\n\n<p>Let\u2019s work with a set of unrelated classes \u2013 <code>AirPollution<\/code>, <code>Discrimination<\/code>, and <code>Deforestation<\/code>. These classes represent things that harm our planet. To quantify the harm, each of these classes define methods that return an int value, like, <code>getAQI()<\/code>, <code>damagingGenerations()<\/code>, and <code>getTreeDamage()<\/code>. The classes define minimal code to keep it simple:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">class AirPollution {\n    public int getAQI() {\n        return 100;\n    }\n}\n\npublic class Discrimination {\n   public int damagingGenerations() {\n       return 2000;\n   }\n}\npublic class Deforestation {\n   public int getTreeDamage() {\n       return 300;\n   }\n}<\/pre>\n\n\n\n<p>Imagine a class <code>MyEarth<\/code>, with a method, say, <code>getDamage()<\/code> that accepts a method parameter of type <code>Object<\/code>. Depending on the type of the object passed to this method, it calls the relevant method on the method parameter to get a quantifiable number for the amount of harm it is causing to our planet:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class MyEarth {\n   int getDamage(Object obj) {\n       int damage = 0;\n       if (obj instanceof AirPollution) {\n           final AirPollution airPollution = ((AirPollution) obj);\n           damage = airPollution.getDamage();\n       }\n       else if (obj instanceof Discrimination) {\n           Discrimination discrimination = ((Discrimination) obj);\n           damage = discrimination.damagingGenerations();\n       } else if (obj instanceof Deforestation) {\n           Deforestation deforestation = ((Deforestation) obj);\n           damage = deforestation.getTreeDamage();\n       } else {\n           damage = -1;\n       }\n       return damage;\n   }\n}<\/pre>\n\n\n\n<p>Let\u2019s look at how we can use switch expressions and IntelliJ IDEA to make this code more concise:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-4.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>Here\u2019s the final (concise) code for reference:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class MyEarth {\n    int getDamage(Object obj) {\n        return switch (obj) {\n            case final AirPollution airPollution -&gt; airPollution.getDamage();\n            case Discrimination discrimination -&gt; discrimination.damagingGenerations();\n            case Deforestation deforestation -&gt; deforestation.getTreeDamage();\n            case null, default -&gt; -1;\n        };\n    }\n}<\/pre>\n\n\n\n<p>The power of this construct lies in how often it helps to reduce the cognitive complexity in the code, as I discuss in the following section.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Reducing cognitive complexity with pattern matching for switch<\/strong><\/h3>\n\n\n\n<p>An if-else statement chain <em>seems<\/em> complex to read and understand \u2013 each condition should be <em>carefully<\/em> read together with its then-and-else code blocks. If we consider the if statement chain from the preceding section, it can be represented roughly as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-img4.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Now let me represent the switch construct from the preceding section:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-img5.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Even by looking at both these images, the switch logic (though similar) looks simpler to read and understand. An if statement chain <em>seems<\/em> to represent a <em>long<\/em>, <em>complex<\/em> path, in which the next turn <em>seems<\/em> to be unknown. But this isn\u2019t the case with the switch construct.<\/p>\n\n\n\n<p>Let\u2019s look at other reasons for working with pattern matching for switch.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Yay! You can now handle nulls within a switch construct<\/strong><\/h3>\n\n\n\n<p>Previously, switch constructs never allowed using null as a case label, even though it accepted instances of class <code>String<\/code> and enumerations. Then how was it possible to test whether the reference variable you are switching over is not null?&nbsp;<\/p>\n\n\n\n<p>One approach has been to add a <code>@NotNull<\/code> annotation to the variable accepted by the switch construct. You can add this annotation to a method argument, a local variable, field, or static variable. Another approach (much widely used) has been to check if the variable is not null by using an if condition.&nbsp;<\/p>\n\n\n\n<p>Of course, if you do not explicitly check for null values and the selector expression is null, it throws a <code>NullPointerExpression<\/code>. For backward compatibility, the <code>null<\/code> selector expression won\u2019t match the default label.<\/p>\n\n\n\n<p>Now, you can define null as one of the valid case labels \u2013 so that you can define what to do if the selector expression is null.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-5.gif\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Does IntelliJ IDEA convert your if-statement to a switch expression or a switch statement?<\/strong><\/h3>\n\n\n\n<p>In the preceding example, the if-else construct was converted to a switch expression. However, if you\u2019d have selected this conversion, <em>before<\/em> using pattern matching for instanceof, you would have got a switch statement, as shown in the following gif:&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-6.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>Since the code block for if-else in the original code snippet defined multiple lines of code, it made sense to convert it to a switch statement rather than a switch expression.<\/p>\n\n\n\n<p>This brings us to another interesting question \u2013 what is the relation between switch statement, switch expression, colon syntax, and arrow syntax? Let\u2019s have a look.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Switch statements vs. Switch expressions and Colon Syntax vs. Arrow Syntax<\/strong><\/h3>\n\n\n\n<p>A switch is classified as a statement or an expression depending on whether it returns a value or not. If it returns a value, it is a switch expression, otherwise a statement. Switch can also use either a colon or an arrow syntax.&nbsp;<\/p>\n\n\n\n<p>Interestingly, the switch style (statement or expression) and arrow\/colon syntax are orthogonally related, as shown in the following image:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-img6.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>The preceding matrix is not just limited or specific to switch statements or expressions that define a pattern in their case labels. It applies to switch statements and expressions that define constants too.<\/p>\n\n\n\n<p>As shown in the previous examples, the case labels are no longer limited to constants. Let\u2019s see what they have to offer.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Type pattern \u2013 case labels with a data type<\/strong><\/h3>\n\n\n\n<p>In the previous examples, case labels included a data type. This is a type pattern. A type pattern compares the selector expression with a type. If the test passes, the value is cast and assigned to the pattern variable that is defined right after the type name. Let\u2019s pull the exact lines of code from these previous examples:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">case Discrimination discrimination -&gt; discrimination.damagingGenerations();\n\ncase Discrimination d -&gt; {\n    Discrimination discrimination = ((Discrimination) obj);\n    damage = discrimination.damagingGenerations();\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Scope of pattern variables<\/strong><\/h3>\n\n\n\n<p>Pattern variables are local variables, which are casted and initialized when a type pattern tests true. Their scope is limited to the case labels in which they are declared \u2013 it doesn\u2019t make sense for a pattern variable to be available in a switch branch in which its argument doesn\u2019t match.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>When do missing break statements in a switch statement become a compilation error?<\/strong><\/h3>\n\n\n\n<p>In the following example, the pattern variable <code>d<\/code> is limited to the case label <code>Discrimination<\/code>. When patterns, instead of constants, are used in case labels for switch statements or expressions, missing <code>break<\/code> statements is a compilation error because it can result in a default fall-through to a case label that did not pass the test:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-7-1.gif\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Guarded patterns \u2013 conditions that follow test patterns<\/strong><\/h3>\n\n\n\n<p>Guarded patterns can help you to add conditions to your case labels, beyond test patterns, so that you don\u2019t have to define another if construct within a switch branch.<\/p>\n\n\n\n<p>Let\u2019s revisit a switch construct from a previous section:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class MyEarth {\n    int getDamage(Object obj) {\n        return switch (obj) {\n            case AirPollution airPol -&gt; airPol.getDamage();\n            case Deforestation deforestation -&gt; deforestation.getTreeDamage();\n            case null, default -&gt; -1;\n        };\n    }\n}<\/pre>\n\n\n\n<p>Imagine you want to return the value 5000, if the <code>getAQI()<\/code> method on an <code>AirPollution<\/code> instance returns a value of more than 200. We are talking about two conditions here:<\/p>\n\n\n\n<ol>\n<li>The variable obj is an instance of <code>AirPollution<\/code><\/li>\n\n\n\n<li><code>airPol.getAQI()<\/code> &gt; 200<\/li>\n<\/ol>\n\n\n\n<p>With the guarded patterns, you can add this condition to the case label, as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class MyEarth {\n    int getDamage(Object obj) {\n        return switch (obj) {\n            case AirPollution airPol &amp;&amp; airPol.getAQI() &gt; 200 -&gt; 500;\n            case Deforestation deforestation -&gt; deforestation.getTreeDamage();\n            case null, default -&gt; -1;\n        };\n    }\n}<\/pre>\n\n\n\n<p>It is interesting to note that when you pass an <code>AirPollution<\/code> instance with <code>getAQI()<\/code> value &lt;= 200, <code>getDamage()<\/code> method will execute the default branch and return -1.&nbsp;<\/p>\n\n\n\n<p>Imagine adding multiple conditions to a switch label after the type patterns. While using operators like the conditions OR and AND, the order of execution can be unclear. In this case you can use parentheses to remove all ambiguities. Here\u2019s an example that would return 500 when <code>getDamage()<\/code> is called passing it an instance of <code>AirPollution<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class MyEarth {\n    int getDamage(Object obj) {\n        return switch (obj) {\n            case AirPollution air\n                    &amp;&amp;\n                    air.getAQI() &gt; 99 || (air.getDamage() &lt; 101 &amp;&amp; air.getRate() &gt; 11) -&gt; 500;\n            case Discrimination discrimination -&gt; discrimination.damagingGenerations();\n            case Deforestation deforestation -&gt; deforestation.getTreeDamage();\n            case null, default -&gt; -1;\n        };\n    }\n}<\/pre>\n\n\n\n<p>If I modify the placement of the parentheses from the preceding code (as shown in the following code snippet), calling <code>getDamage()<\/code> passing it an instance of <code>AirPollution<\/code> would return -1:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class MyEarth {\n    int getDamage(Object obj) {\n        return switch (obj) {\n            case AirPollution air\n                    &amp;&amp;\n                    (air.getAQI() &gt; 99 || air.getDamage() &lt; 101) &amp;&amp; air.getRate() &gt; 11 -&gt; 500;\n            case Discrimination discrimination -&gt; discrimination.damagingGenerations();\n            case Deforestation deforestation -&gt; deforestation.getTreeDamage();\n            case null, default -&gt; -1;\n        };\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Parenthesized patterns<\/strong><\/h3>\n\n\n\n<p>So far, the necessity of parenthesized patterns is very low. It&#8217;s only to distinguish guard and expression in instanceof syntax: <code>if(o instanceof (String s &amp;&amp; !s.isEmpty())<\/code> &#8212; here we use a parenthesized pattern (with guarded pattern inside). It will be more useful in the future with deconstruction patterns.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Pattern dominance \u2013 handling general types before specific types in case labels<\/strong><\/h3>\n\n\n\n<p>What happens if the types being checked in switch case labels have an inheritance relationship? You should check for the most specific case, prior to checking for the general type.&nbsp;<\/p>\n\n\n\n<p>Failing to do so would be a compilation error \u2013&nbsp; as shown in the following image, when the code in method <code>getDamageForDifferentPollutionTypes<\/code> compares its method parameter <code>obj<\/code> with class <code>AirPollution<\/code> and <code>Pollution<\/code> (class <code>AirPollution<\/code> extends <code>Pollution<\/code>).&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-img7.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>An interesting observation is that with a similar logic it isn\u2019t a compilation error for an if-else statement.<\/p>\n\n\n\n<p>However, in such cases, IntelliJ IDEA would not offer you the option to convert it to a switch. You get the option, when you remove checking a superclass before its subclass, or, perhaps checking for unrelated types:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-8.gif\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Should you care about handling all possible values for the selector expression in switch?<\/strong><\/h3>\n\n\n\n<p>Yes, you must have a branch to execute, regardless of the value that is passed to it, if you are using any kind of patterns in case labels with switch expressions or switch statements.<\/p>\n\n\n\n<p>Imagine the following hierarchy of classes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">abstract class Pollution {}\nclass WaterPollution extends Pollution {}\nclass AirPollution extends Pollution {}<\/pre>\n\n\n\n<p>Defining a case label which handles instances of type Pollution as the last case label might look obvious in the following code, since switch is returning a value. Since the switch is switching over a reference variable of type pollution, it can be assigned a value of type Pollution or one of its subclasses. In this case a default label is not required:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">class MyEarth {\n    static int getDamageForDifferentPollutionTypes(Pollution pollution) {\n        return switch (pollution) {\n            case WaterPollution w -&gt; 100;\n            case AirPollution a -&gt; 200;\n            case Pollution p -&gt; 300;\n        };\n    }\n}<\/pre>\n\n\n\n<p>Also, you would need to handle all the possible values for method parameter pollution, even when the switch-statement is not returning a value:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">class MyEarth {\n    static void getDamageForDifferentPollutionTypes(Pollution pollution) {\n        switch (pollution) {\n            case WaterPollution w -&gt; System.out.println(100);\n            case AirPollution a -&gt; System.out.println(200);\n            case Pollution p -&gt; System.out.println(300);\n        };\n    }\n}<\/pre>\n\n\n\n<p>Or when using an old-style colon syntax:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">class MyEarth {\n    static void getDamageForDifferentPollutionTypes(Pollution pollution) {\n        switch (pollution) {\n            case WaterPollution w :\n                System.out.println(100);\n                break;\n            case AirPollution a :\n                System.out.println(200);\n                break;\n            case Pollution p : \n                System.out.println(300);\n                break;\n        };\n    }\n}<\/pre>\n\n\n\n<p>Adding a null case to switch is not mandatory to ensure that it handles all the possible values.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Using sealed classes as type patterns \u2013 are they treated differently to non-sealed classes?<\/strong><\/h3>\n\n\n\n<p>The short answer is yes they are. Please refer to the section \u2018Sealed classes and interfaces\u2019 below in this blog post for their detailed coverage.<\/p>\n\n\n\n<p>Let\u2019s revisit the hierarchy of the Pollution classes from our previous example and modify it by sealing it:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">sealed abstract class Pollution {}\nfinal class WaterPollution extends Pollution {}\nnon-sealed class AirPollution extends Pollution {}<\/pre>\n\n\n\n<p>Now the compiler is sure that the abstract class Pollution has exactly <em>two<\/em> subclasses. So you can handle values passed to method parameter pollution, as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">class MyEarth {\n    static int getDamageForDifferentPollutionTypes(Pollution pollution) {\n        return switch (pollution) {\n            case WaterPollution w -&gt; 100;\n            case AirPollution a -&gt; 200;\n            \/\/ case Pollution is no longer required\n        };\n    }\n}<\/pre>\n\n\n\n<p>This rule applies to the hierarchy of an interface too.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Freedom from defining code that might never execute<\/strong><\/h3>\n\n\n\n<p>To understand what that freedom means, let\u2019s look at an example of a sealed interface and the classes that implement it:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">sealed interface Expandable {}\nrecord Circle(int radius) implements Expandable {}\nrecord Square(int side) implements Expandable {}<\/pre>\n\n\n\n<p>Without pattern matching for switch, the if statement in the following code would require you to define an else part even though you have handled both the implementing classes of the interface <code>Expandable<\/code>, that is, <code>Circle<\/code> and <code>Square<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class Geometry {\n    double getArea(Expandable expandable) {\n        if (expandable instanceof Circle c) {\n            return 3.14 * c.radius() * c.radius();\n        }\n        else if (expandable instanceof Square s) {\n            return s.side() * s.side();\n        }\n        else {\n            return -1; \/\/ This code might never execute\n        }\n    }\n}<\/pre>\n\n\n\n<p>However, this changes when you use pattern matching for switch, as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class Geometry {\n    double getArea(Expandable expandable) {\n        return switch (expandable) {\n            case Circle c -&gt; 3.14 * c.radius() * c.radius();\n            case Square s -&gt; s.side() * s.side();\n        };\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Running the &#8220;if can be replaced with switch&#8221; inspection on your code base&nbsp;<\/strong><\/h3>\n\n\n\n<p>It can be time-consuming to look for if-else constructs in your code and check if they can be replaced with switch. You can run the inspection \u2018if can be replaced with switch\u2019 on all the classes in your codebase or its subset.<\/p>\n\n\n\n<p>With this inspection, you can convert <em>most<\/em> of the if-statements to switch. I stated \u2018most\u2019 of the if-statements and not \u2018all\u2019, for a reason. As demonstrated using a lot of examples in the preceding section, you\u2019ll notice that at times IntelliJ IDEA won\u2019t offer you an option to convert an if-else statement to switch, or it might not convert it the way you have assumed it would. This is due to missing adherence to the multiple rules we talked about in this blog.<\/p>\n\n\n\n<p>To run the &#8220;if can be replaced with switch&#8221; inspection, you can use the feature \u2013 &#8220;Run inspection by name&#8221;, using the shortcut Ctrl+Alt+Shift+I or \u2325\u21e7\u2318I. Enter the inspection name, followed by selecting the scope and other options. The Problems Tool window will show you where you can apply this inspection. You can choose to apply or ignore the suggested changes as you browse the list in the Problems View Window.&nbsp;&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/09\/java17-9.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>We have talked a lot about the pattern matching for switch. Now let\u2019s cover sealed classes and interfaces. Added as a standard language feature in Java 17, they haven\u2019t changed from Java 16.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\"><strong>Sealed classes and interfaces (now a standard feature)<\/strong><\/h1>\n\n\n\n<p>The language syntax of Sealed types enables you to restrict the classes or interfaces that can extend or implement them. The goal of this language feature is to let you define the possible hierarchies in your business domain in a declarative manner. But why would you ever need to create restricted hierarchies?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Need for creating restricted hierarchies<\/strong><\/h2>\n\n\n\n<p>Imagine you are creating an application that helps its users with gardening activities. Depending on the type of plant, a gardener might need to do different activities. Let\u2019s model the plant hierarchy as follows (I\u2019m not detailing the classes on purpose):<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">class Plant {}\n\nclass Herb extends Plant {}\nclass Shrub extends Plant {}\nclass Climber extends Plant {}\n\nclass Cucumber extends Climber {}<\/pre>\n\n\n\n<p>The following code is an example of how the <code>Gardener<\/code> class might use this hierarchy:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public class Gardener {\n   int process(Plant plant) {\n       if (plant instanceof Cucumber) {\n           return harvestCucumber(plant);\n       } else if (plant instanceof Climber) {\n           return sowClimber(plant);\n       } else if (plant instanceof Herb) {\n           return sellHerb(plant);\n       } else if (plant instanceof Shrub) {\n           return pruneShrub(plant);\n       } else {\n           System.out.println(&quot;Unreachable CODE. Unknown Plant type&quot;);\n           return 0;\n       }\n   }\n\n   private int pruneShrub(Plant plant) {...}\n   private int sellHerb(Plant plant) {...}\n   private int sowClimber(Plant plant) {...}\n   private int harvestCucumber(Plant plant) {...}\n}<\/pre>\n\n\n\n<p>The problem code is the assumption that a developer has to deal with in the last else construct &#8211; defining actions even though the developer knows that all possible types of the method parameters plant have been addressed. Though it might look unreachable now, what happens if another developer adds a class to this hierarchy? Sealed classes can impose this restriction on the hierarchies at the language level.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Define secure hierarchies with sealed classes<\/strong><\/h2>\n\n\n\n<p>With the <a href=\"https:\/\/openjdk.java.net\/jeps\/8223002#:~:text=Contextual%20keyword%3A%20A%20sequence%20of,declarations%2C%20since%20Java%209\" target=\"_blank\" rel=\"noopener\">contextual keyword<\/a> sealed, you can <strong>declare<\/strong> a class as a sealed class. A sealed class uses the <a href=\"https:\/\/openjdk.java.net\/jeps\/8223002#:~:text=Contextual%20keyword%3A%20A%20sequence%20of,declarations%2C%20since%20Java%209\" target=\"_blank\" rel=\"noopener\">contextual keyword<\/a> permits to list the classes that can extend it directly. Its subclasses can either be final, non-sealed<em>,<\/em> or sealed.&nbsp;<\/p>\n\n\n\n<p>The following gif shows how you can use IntelliJ IDEA to change the declaration of a regular class to a sealed class (by using the context action \u2018Seal class\u2019). By default, IntelliJ IDEA declares all derived classes as non-sealed. You can modify it to be <code>final<\/code> or <code>sealed<\/code>:&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/wO_grmMXfKLDbfW4olxIRkrdPJRYDhyoWOcoUM-JTZUnlF5D000JrE6vD08gbNAFwabDdZFHVIC9-KPh4GfFCex57Pm2oorXjqZt8gRJEmhTOONJMgsgreeBN5ReK-KGQXlf-Q3Ds0.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>Here\u2019s the modified code for reference:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">public sealed class Plant permits Herb, Shrub, Climber {\n}\n\npublic final class Shrub extends Plant {}\npublic non-sealed class Herb extends Plant {}\npublic sealed class Climber extends Plant permits Cucumber{}\n\npublic final class Cucumber extends Climber {}<\/pre>\n\n\n\n<p>By allowing a predefined set of classes to extend your class, you can <strong>decouple accessibility from extensibility<\/strong>. You can make your sealed class accessible to other packages and modules, and you can still control who can extend it.&nbsp;<\/p>\n\n\n\n<p>In the past, to prevent classes from being extended, developers created package-private classes. But, this also meant that these classes had limited accessibility. Another approach to prevent extension was to create public classes with private or package-private constructors. Though it enabled a class to be visible, it gave limited control on the exact types that could extend your class.&nbsp;<\/p>\n\n\n\n<p>This is no longer the case if you use sealed classes. The goal of the Sealed types is to model your business domain, so that you process it in a definitive manner.&nbsp;<\/p>\n\n\n\n<p>You can\u2019t create another class, say, <code>AquaticPlant<\/code>, that tries to extend the sealed class Plant, without adding it to the permits clause of the class <code>Plant<\/code>. As shown in the following gif, this is a compilation error:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/DL4Yi0XavZK8P5ZER2TlX8v-r5CIzBMVjOmmN69bCmRG-Cmq7PS4DBSwoqDKXCZiRv5n2fGvnfnvXTPLzG9VnREFX8sBvA_XCpH6dpmOsLTcIUyOVnr5H0uEC-Reij2g48pHosJWs0.gif\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Revisiting processing of Plant types in class Gardener<\/strong><\/h2>\n\n\n\n<p>After creating a sealed hierarchy, you will be able to process an instance from the hierarchy in a precise way, and won\u2019t need to deal with any unknown implementations. The <code>process<\/code> method in class <code>Gardener<\/code> will work with no chance of running the <code>else<\/code> clause. However, the syntax of the if-else construct will still need you to define the else part (this may change in a future Java version).<\/p>\n\n\n\n<p><em>Type-test-patterns<\/em>, introduced with Pattern Matching for instanceof in Java 14, are added to the switch statements and expressions. This lets you eliminate the definition of code to execute for an unmatched <code>Plant<\/code> type passed to the method <code>process()<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">int process(Plant plant) {\n   return switch (plant) {\n       case Cucumber c -&gt; c.harvestCucumber();\n       case Climber cl -&gt; cl.sowClimber();\n       case Herb h -&gt; h.sellHerb();\n       case Shrub s -&gt; s.pruneShrub();\n   }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Package and module restrictions&nbsp;<\/strong><\/h2>\n\n\n\n<p>Sealed classes and their implementations can\u2019t span across multiple Java modules.&nbsp;<\/p>\n\n\n\n<p>If a sealed base class is declared in a named Java module, all its implementations must be defined in the same module. However, they can appear in different packages.&nbsp;<\/p>\n\n\n\n<p>For a sealed class declared in an unnamed Java module, all its implementations must be defined in the same package.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Rules for base and extended classes<\/strong><\/h2>\n\n\n\n<p>The classes that extend a sealed class must either be final, non-sealed, or sealed. A final class prohibits further extension. A non-sealed class allows other classes to extend it. And a sealed<em> <\/em>subclass must follow the same set of rules as the parent base class \u2013 it could be extended by an explicit list of other classes.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Abstract sealed base class&nbsp;<\/strong><\/h2>\n\n\n\n<p>A sealed class can be abstract too. The extended classes could be defined as abstract or concrete classes. Here\u2019s the modified code which adds an abstract method <code>grow()<\/code> to the class <code>Plant<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">sealed abstract public class Plant permits Herb, Shrub, Climber {\n   abstract void grow();\n}\n\npublic final class Shrub extends Plant {\n   @Override\n   void grow() {\n   }\n}\n\npublic non-sealed abstract class Herb extends Plant {}\n\npublic sealed class Climber extends Plant permits Cucumber{\n   @Override\n   void grow() {\n   }\n}\n\nfinal class Cucumber extends Climber {}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Implicit subclasses<\/strong><\/h2>\n\n\n\n<p>If you define a sealed class and its derived classes in the same source file, you can omit the contextual keyword permits and the name of the derived classes that are included in the declaration of a sealed class. In this case, the compiler can infer the hierarchy.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/xzlgIYLYBNICSpdXjJgWCCb5C4slW5LLoRF9Dq9NB-Q7WuwUdqR7bdToJkbs-pyVH_nQbbOQy-DChZRHSxnuz6_pRZJbug8dPzyiKen4uyILnQg4eSN4Ml_JocWKKQ-9WczN8yy9s0.gif\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Sealed interfaces<\/strong><\/h2>\n\n\n\n<p>Unlike classes, interfaces can not define constructors. Before the introduction of <em>sealed classes<\/em>, a public class could define a private or package-private constructor to limit its extensibility, but interfaces couldn\u2019t do that.&nbsp;<\/p>\n\n\n\n<p>A sealed interface allows you to explicitly specify the interfaces that can extend it and the classes that can implement it. It follows rules similar to sealed classes.&nbsp;<\/p>\n\n\n\n<p>However, since you can\u2019t declare an interface using the modifier final \u2013 because doing so&nbsp; would clash with its purpose, as interfaces are meant to be implemented \u2013 an inheriting interface can be declared using either sealed or non-sealed modifiers. The permits clause of an interface declaration lists the classes that can directly implement a sealed interface and interfaces that can extend it. An implementing class can be either final, sealed, or non-sealed:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/XFTePwAnaj8L5idDHi-mbdAlwluK-guL9z-nVOpCd2y9RIVQc8IxtYH_KZ3jzFMPu82XsAd6mG-gEsWkkrKJzlY8o_7zmjQX9GCp-biUhl5C7kbMo2DvuPyb6wiX7Dmrr_0LSSbOs0.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>Here\u2019s the code for reference:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">sealed public interface Move permits Athlete, Jump, Kick {\n}\n\nfinal class Athlete implements Move {}\nnon-sealed interface Jump extends Move {}\nsealed interface Kick extends Move permits Karate {}\n\nfinal class Karate implements Kick {}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Stronger code analysis with closed list of subclasses<\/strong><\/h2>\n\n\n\n<p>With sealed classes and interfaces, you can have an explicit list of inheritors that is known to the compiler, IDE and the runtime (via reflection). This closed list of subclasses makes the code analysis more powerful.<\/p>\n\n\n\n<p>For example, consider the following completely sealed hierarchy of <code>WritingDevice<\/code> (which doesn\u2019t have non-sealed subtypes):<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">interface Erasable {}\n\nsealed class WritingDevice permits Pen, Pencil {}\nfinal class Pencil extends WritingDevice {}\nsealed class Pen extends WritingDevice permits Marker {}\nfinal class Marker extends Pen {}<\/pre>\n\n\n\n<p>Now, instanceof and casts can check the complete hierarchy statically. Code on line1 and line2 are compilation errors. The compiler checks all the inheritors from the permits list and finds that no one of them implements the <code>Erasable<\/code> or the <code>CharSequence<\/code> interface:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">class UseWritingDevice {\n   static void write(WritingDevice pen) {\n       if (pen instanceof Erasable) {                   \/\/ line1\n       }\n       CharSequence charSequence = ((CharSequence) pen);\/\/ line2\n   }\n}<\/pre>\n\n\n\n<p>The following gif demonstrates it in IntelliJ IDEA:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/tHpt2ZISzzPS4hYpuSiXaWTrTiz7vUufr6xq7LOvuyrlOB4pSG_MrRll_IcFI_QbXIpKUpDcW15_1Ib0J4eFdtE87btbBakLOrPa2iYeyB96xe26QbMgf2pq0eBAbkje7bF-S887s0.gif\" alt=\"\"\/><\/figure>\n\n\n\n<p>I mentioned that Pattern Matching for switch is introduced as a preview language feature in Java 17. Just in case you are unaware of what preview features mean, I\u2019ve covered it in the next section.&nbsp;<\/p>\n\n\n\n<h1 class=\"wp-block-heading\"><strong>Preview Features<\/strong><\/h1>\n\n\n\n<p>With Java\u2019s new release cadence of six months, new language features are released as preview features. They may be reintroduced in later Java versions in the second or third preview, with or without changes. Once they are stable enough, they may be added to Java as a standard language feature.&nbsp;<\/p>\n\n\n\n<p>Preview language features are complete but not permanent, which essentially means that these features are ready to be used by developers, although their finer details could change in future Java releases depending on developer feedback. Unlike an API, language features can\u2019t be deprecated in the future. So, if you have feedback about any of the preview language features, feel free to share it on the <a href=\"https:\/\/mail.openjdk.java.net\/mailman\/listinfo\/amber-dev\" target=\"_blank\" rel=\"noopener\">JDK mailing list<\/a> (free registration required).<\/p>\n\n\n\n<p>Because of how these features work, IntelliJ IDEA is committed to only supporting preview features for the current JDK. Preview language features can change across Java versions, until they are dropped or added as a standard language feature. Code that uses a preview language feature from an older release of the Java SE Platform might not compile or run on a newer release. For example, Switch Expressions in Java 12 were released with the usage of break to return a value from its branch, which was later changed to yield. Support for using break to return a value from Switch Expressions has already been dropped in IntelliJ IDEA.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\"><strong>Summary<\/strong><\/h1>\n\n\n\n<p>IntelliJ IDEA is not only committed to supporting new Java features, but also to ensuring that our existing intentions and inspections work with them.&nbsp;<\/p>\n\n\n\n<p>IntelliJ IDEA 2021.2.1 supports basic support for the pattern matching for switch. More support is in the works. This version has full support for recent additions like sealed classes and interfaces, records, and pattern matching for instanceof.<\/p>\n\n\n\n<p>We love to hear from our users. Don\u2019t forget to submit your feedback regarding the support for these features in IntelliJ IDEA.<\/p>\n\n\n\n<p>Happy Developing!<\/p>\n\n\n\n<p><\/p>\n","protected":false},"author":921,"featured_media":178111,"comment_status":"closed","ping_status":"closed","template":"","categories":[4759],"tags":[6742,6743,6744,6746,6747,6745,3374,155],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea\/176262"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/users\/921"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/comments?post=176262"}],"version-history":[{"count":9,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea\/176262\/revisions"}],"predecessor-version":[{"id":639484,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/idea\/176262\/revisions\/639484"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/media\/178111"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/media?parent=176262"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/categories?post=176262"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/tags?post=176262"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/cross-post-tag?post=176262"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}