{"id":73628,"date":"2020-09-09T14:16:39","date_gmt":"2020-09-09T14:16:39","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=73628"},"modified":"2021-10-04T14:56:37","modified_gmt":"2021-10-04T13:56:37","slug":"java-15-and-intellij-idea","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/ja\/idea\/2020\/09\/java-15-and-intellij-idea","title":{"rendered":"Java 15 and IntelliJ IDEA"},"content":{"rendered":"<p>Java 15 introduces a new language feature \u2013 <a href=\"https:\/\/openjdk.java.net\/jeps\/360\" target=\"_blank\" rel=\"noopener\">sealed classes and interfaces<\/a>. The language syntax allows you to restrict the classes or interfaces that can extend or implement other classes or interfaces. The goal is to let you define the possible hierarchies in your business domain in a declarative manner, so that it is easier to process them. This language feature is introduced as a <a href=\"https:\/\/openjdk.java.net\/jeps\/12\" target=\"_blank\" rel=\"noopener\">preview language feature<\/a>.<\/p>\n<p>Java 15 also modifies the preview language feature <a href=\"https:\/\/openjdk.java.net\/jeps\/384\" target=\"_blank\" rel=\"noopener\">Records<\/a>, introduced in Java 14, and enhances the interfaces and enums you are used to working with. <a href=\"https:\/\/openjdk.java.net\/jeps\/375\" target=\"_blank\" rel=\"noopener\">Pattern Matching for instanceof<\/a>, introduced as a preview language feature in Java 14, is in its second preview in Java 15, without any changes. Introduced in Java 13, <a href=\"https:\/\/openjdk.java.net\/jeps\/368\" target=\"_blank\" rel=\"noopener\">Text Blocks<\/a> are being added to Java 15 as a standard language feature. There are no changes to Text Blocks from Java 14.<\/p>\n<p>In this article, I will cover all the new and updated language features in Java 15, why you need them, and I\u2019ll show you how to use them in <a href=\"https:\/\/jb.gg\/tgrb3m\" target=\"_blank\" rel=\"noopener\">IntelliJ IDEA<\/a>. Let\u2019s get started.<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/linkedlin_1200x628.png\" alt=\"\"><br \/>\n<!--more--><\/p>\n<h2>Sealed classes and interfaces (a preview language feature)<\/h2>\n<p>By defining a class as a <em>sealed class<\/em>, you can explicitly define which other classes can extend it. On the one hand, it lets you reuse a class with inheritance, and on the other hand, it lets you restrict which classes can extend it. But why would you need to create restricted hierarchies?<\/p>\n<h3>Need for creating restricted hierarchies<\/h3>\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<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">class Plant {}\n\nclass Herb extends Plant {}\nclass Shrub extends Plant {}\nclass Climber extends Plant{}\n\nclass Cucumber extends Climber {}<\/pre>\n<p>The following is an example of how the Gardener class might use this hierarchy:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class Gardner {\n   int process(Plant plant) {\n       if (plant instanceof Cucumber) {\n           return harvestCucumber();\n       } else if (plant instanceof Climber) {\n           return sowClimber();\n       } else if (plant instanceof Herb) {\n           return sellHerb();\n       } else if (plant instanceof Shrub) {\n           return pruneShrub();\n       } else {\n           System.out.println(&quot;Unreachable CODE. Unknown Plant type&quot;);\n           return 0;\n       }\n   }\n\n   private int pruneShrub() { .. }\n   private int sellHerb() { .. }\n   private int sowClimber() { .. }\n   private int harvestCucumber() { .. }\n}<\/pre>\n<p>The problem code is the assumption that a developer has to deal with in the <code>else<\/code> part. Though 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.<\/p>\n<h3>Define secure hierarchies with sealed classes<\/h3>\n<p>With the modifier <code>sealed<\/code>, you can declare a class as a sealed class. A sealed class uses the reserved keyword <code>permits<\/code> to list the classes that can extend it directly. The subclasses can either be final, non-sealed, or sealed.<\/p>\n<p>The following gif shows how to change the declaration of a regular class to a sealed class and modify the declaration of the classes that extend it:<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/create-sealed-class-cover.png\" alt=\"\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/create-sealed-class.gif\"><\/p>\n<p>Here\u2019s the modified code for reference:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nsealed public class Plant permits Herb, Shrub, Climber {\n}\n\nfinal class Herb extends Plant {}\nnon-sealed class Shrub extends Plant {}\nsealed class Climber extends Plant permits Cucumber{}\n\nfinal class Cucumber extends Climber {}<\/pre>\n<p>By allowing a predefined set of classes to extend your class, you can decouple accessibility from extensibility. You can make your sealed class accessible to other packages and modules, but you can still control who can extend it. In the past, to prevent classes from being extended, developers created package-private classes. However, this also meant that these classes had limited accessibility. This is no longer the case if you use sealed classes.<\/p>\n<p>You can get the permitted subclasses via reflection using the <code>Class.permittedSubclasses()<\/code> method. This makes it possible to enumerate the complete sealed hierarchy at runtime, which can be useful.<\/p>\n<p>Let\u2019s quickly check the configuration of IntelliJ IDEA on your system to ensure you can get the code running it.<\/p>\n<h3>IntelliJ IDEA Configuration<\/h3>\n<p>Java 15 features are supported in <a href=\"https:\/\/jb.gg\/tgrb3m\" target=\"_blank\" rel=\"noopener\">IntelliJ IDEA<\/a> 2020.2, which was released in July 2020. You can configure it to use Java 15 by selecting the Project SDK as 15 and choosing the \u2018Project language level\u2019 as \u201815 (Preview) \u2013 Sealed types, records, patterns, local enums and interfaces\u2019 for your Project and Modules settings.<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/ij-java15-config.png\" alt=\"\" width=\"803\"><\/p>\n<p>Java 15 will be GA (General Availability) on September 15, 2020, after which you will also be able to download it directly from IntelliJ IDEA. To do so, click on SDKs, under \u2018Platform Settings\u2019, then click the \u2018+\u2019 sign at the top, choose \u2018Download JDK\u2019, then select the Vendor and the version and the directory to download the JDK to.<\/p>\n<h3>Revisiting processing of Plant types in class Gardner<\/h3>\n<p>After creating a sealed hierarchy, you will be able to process an instance from the hierarchy in a precise manner and won\u2019t need to deal with any \u2018general\u2019 implementations. The <code>process<\/code> method in class <code>Gardner<\/code> will work with no chance of running the <code>else<\/code> clause. However, the syntax of the <code>if<\/code>&#8211;<code>else<\/code> construct will still need you to define the <code>else<\/code> part (this may change in a future Java version).<\/p>\n<p><em>Type-test-patterns<\/em>, introduced with Pattern Matching for instanceof in Java 14, might be added to the switch expressions in future Java versions. With the enhanced switch expressions, you are able to work with the exhaustive list of extended types. This lets you eliminate the definition of any \u2018general code\u2019 to execute for an unmatched <code>Plant<\/code> type passed to the method <code>processInAFutureJavaVersion<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n\/\/ This code doesn&#039;t work in Java 15.\n\/\/ It would work in a future Java version after the addition of \n\/\/ type-test-pattern to the switch expressions\nint processInAFutureJavaVersion(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<h3>Package and module restrictions<\/h3>\n<p>Sealed classes and their implementations can\u2019t span across multiple modules. If a sealed base class is defined in a named module, all its implementations must be defined in the same module. However, they can appear in different packages.<\/p>\n<p>For a sealed class defined in an unnamed module, all its implementations must be defined in the same package.<\/p>\n<h3>Rules for base and extended classes<\/h3>\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 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.<\/p>\n<p>A sealed class can be abstract too. The extended classes could be defined as abstract or concrete classes.<\/p>\n<p>Let\u2019s modify the set of classes I used in the preceding section and define the class <code>Plant<\/code> as an abstract class with an abstract method <code>grow()<\/code>. Since the derived class <code>Herb<\/code> is a final class, it must implement the method <code>grow()<\/code>. The non-sealed derived class <code>Shrub<\/code> is now an abstract class, and it may not implement the method <code>grow()<\/code>. The sealed derived class <code>Climber<\/code> implements the abstract method <code>grow()<\/code>, if it doesn\u2019t need to be defined as an abstract class:<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/abstract-sealed-types-cover.png\" alt=\"\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/abstract-sealed-types.gif\"><\/p>\n<p>Here\u2019s the modified code for reference:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nsealed abstract public class Plant permits Herb, Shrub, Climber {\n   abstract void grow();\n}\n\nfinal class Herb extends Plant {\n   @Override\n   void grow() {\n   }\n}\n\nnon-sealed abstract class Shrub extends Plant {}\n\nsealed class Climber extends Plant permits Cucumber{\n   @Override\n   void grow() {\n   }\n}\n\nfinal class Cucumber extends Climber {}<\/pre>\n<p>If you define a sealed class and its derived classes in the same source file, you can omit the modifier <code>permits<\/code> 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<h3>Sealed interfaces<\/h3>\n<p>A sealed interface allows you to explicitly specify the interfaces that can extend it and the classes (including records) that can implement it. It follows rules similar to sealed classes.<\/p>\n<p>However, since you can\u2019t declare an interface using modifier <code>final<\/code> \u2013 because doing so would clash with its purpose, as interfaces are meant to be implemented \u2013 an inheriting interface can be declared using either <code>sealed<\/code> or <code>non-sealed<\/code> modifiers. The <code>permits<\/code> 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. Since records, introduced in Java 14, are  implicitly final, they don\u2019t need any additional modifiers:<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/create-sealed-interface-cover.png\" alt=\"\" data-gif-src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/09\/create-sealed-interface.gif\"><\/p>\n<p>Here\u2019s the code for reference:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nsealed public interface Move permits Athlete, Person, Jump, Kick {\n}\n\nfinal class Athlete implements Move {}\nrecord Person(String name, int age) implements Move {}\nnon-sealed interface Jump extends Move {}\nsealed interface Kick extends Move permits Karate {}\n\nfinal class Karate implements Kick {}<\/pre>\n<p>Let\u2019s move on to the next enhancement in Java 15 \u2013 the introduction of local records.<\/p>\n<h2>Records<\/h2>\n<p>A new type of class, Records introduced a compact form to model value objects. A preview language feature in Java 14, Records is in its second preview in Java 15, with a few changes.<\/p>\n<p>If you are new to Records, or if you want to find out how Records are supported in IntelliJ IDEA, please refer to my <a href=\"https:\/\/blog.jetbrains.com\/ja\/idea\/2020\/03\/java-14-and-intellij-idea\">Java 14 and IntelliJ IDEA<\/a> blog post. IntelliJ IDEA has a lot of features to help you create and use Records and this blog post explains it using hands-on examples.<\/p>\n<p>In this blog post, I\u2019ll cover the changes to Records from Java 14 to Java 15.<\/p>\n<p>Java 15 allows you to define local records to model a domain object, while you are processing values in a method. In the following example, the method <code>getTopPerformingStocks<\/code> finds and returns the names of Stocks that have the highest value on a specified date.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nList&lt;String&gt; getTopPerformingStocks(List&lt;Stock&gt; allStocks, LocalDate date) {\n   \/\/ TopStock is a local record\n   record TopStock(Stock stock, double stockValue) {}\n\n   return allStocks.stream()\n              .map(s -&gt; new TopStock(s, getStockValue(s, date)))\n              .sorted((s1, s2) -&gt; Double.compare(s1.stockValue(), s2.stockValue()))\n              .limit(2)\n              .map(s -&gt; s.stock.getName())\n              .collect(Collectors.toList());\n\n}<\/pre>\n<h2>Local interfaces and enums<\/h2>\n<p>Java 15 allows declaration of local enums and interfaces too \u2013 for the same reason. You can encapsulate your data or business logic, which is local to a method, within the method.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic void createLocalInterface() {\n   interface LocalInterface {\n       void aMethod();\n   }\n   \/\/ Code to use LocalInterface\n}\n\npublic void createLocalEnum() {\n   enum Color {RED, YELLOW, BLUE}\n   \/\/ Code to use enum Color\n}<\/pre>\n<p>However, they cannot capture any context variable. For example, for the local enum <code>Data<\/code>, the enum constants <code>FOO<\/code> and <code>BAR<\/code> can\u2019t be created by using the method parameter <code>input<\/code> in the method <code>test()<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nvoid test(int input) {\n   enum Data {\n       FOO(input), BAR(input*2); \/\/ Error. Can\u2019t refer to input\n\n       private final int i;\n\n       Data(int i) {\n           this.i = i;\n       }\n   }\n}<\/pre>\n<h2>Pattern Matching for instanceof<\/h2>\n<p>Many Java developers use the <code>instanceof<\/code> operator to check whether a given reference variable is of a certain type. They compare a reference variable to a type by using the <code>instanceof<\/code> operator. If the result is <code>true<\/code>, the next obvious step is to explicitly cast it to the type they compared it with to access its members. These steps have an obvious repetition here, like <em>compare-ifResultTrue-castToType<\/em>.<\/p>\n<p>In Java 14, the usage of the <code>instanceof<\/code> operator was simplified by the addition of Pattern Matching to the <code>instanceof<\/code> operator. It introduces a pattern variable, so you don\u2019t need additional variables or explicit casting, making your code safer and more concise to write and read.<\/p>\n<p>Pattern Matching for instanceof is in its second preview in Java 15 (without any changes from Java 14).<\/p>\n<p>Please refer to my <a href=\"https:\/\/blog.jetbrains.com\/ja\/idea\/2020\/03\/java-14-and-intellij-idea\">Java 14 and IntelliJ IDEA<\/a> blog post, to find out how IntelliJ IDEA supports this new feature by adding new intentions. This blog post also has some excellent examples of how to refactor your code using this feature and other inspections from IntelliJ IDEA, like merging nested if and extracting or inlining variables.<\/p>\n<h2>Text Blocks<\/h2>\n<p>Multiline Strings, Text Blocks have been added as a standard language feature in Java 15 (without any changes from Java 14).<\/p>\n<p>Please refer to my <a href=\"https:\/\/blog.jetbrains.com\/ja\/idea\/2020\/03\/java-14-and-intellij-idea\">Java 14 and IntelliJ IDEA blog post<\/a>, to find out how IntelliJ IDEA supports Text Blocks and you can use it in your applications.<\/p>\n<h2>Preview Language Features<\/h2>\n<p>Sealed classes and interfaces have been released as a preview language feature in Java 15. 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.<\/p>\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 a future Java release 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<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 a Switch Expression\u2019s 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<h2>Summary<\/h2>\n<p><a href=\"https:\/\/jb.gg\/tgrb3m\" target=\"_blank\" rel=\"noopener\">IntelliJ IDEA<\/a> is not only committed to supporting new Java features, but also to ensuring that our existing intentions and inspections work with them.<\/p>\n<p><a href=\"https:\/\/jb.gg\/tgrb3m\" target=\"_blank\" rel=\"noopener\">IntelliJ IDEA<\/a> 2020.2 already supports all the new language features from Java 15. Try out Sealed classes and interfaces, Records, Pattern Matching for instanceof, and Text Blocks today. You can download it <a href=\"https:\/\/jb.gg\/tgrb3m\" target=\"_blank\" rel=\"noopener\">using this link<\/a>.<\/p>\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<p>Happy Developing!<\/p>\n","protected":false},"author":921,"featured_media":73787,"comment_status":"closed","ping_status":"closed","template":"","categories":[808,4759],"tags":[155,6290,76,6758,3390,3389,6291,3372],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/73628"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/users\/921"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/comments?post=73628"}],"version-history":[{"count":3,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/73628\/revisions"}],"predecessor-version":[{"id":181686,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/73628\/revisions\/181686"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/media\/73787"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/media?parent=73628"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/categories?post=73628"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/tags?post=73628"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/cross-post-tag?post=73628"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}