{"id":443113,"date":"2024-02-11T20:01:03","date_gmt":"2024-02-11T19:01:03","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=443113"},"modified":"2024-02-12T09:44:16","modified_gmt":"2024-02-12T08:44:16","slug":"constructor-makeover-in-java-22","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/pt-br\/idea\/2024\/02\/constructor-makeover-in-java-22","title":{"rendered":"Constructor Makeover in Java 22"},"content":{"rendered":"<p>Typically, we create alternative solutions for tasks that are necessary, but not officially permitted. For instance, executing statements before <code>super()<\/code> in a derived class constructor was not officially allowed, even though it was important for, say, validating values being passed to the base class constructor. A popular workaround involved creating static methods to validate values and then calling these methods on the arguments of <code>super()<\/code>. Though this approach worked well, it could make the code look complicated. This is changing with <a href=\"https:\/\/openjdk.org\/jeps\/447\" target=\"_blank\" rel=\"noopener\">Statements before super()<\/a>, a preview language feature in Java 22.<\/p>\n<p>By using this feature, you can opt for a more direct approach, that is, drop the workaround of creating static methods, and execute code that  validates arguments, just before calling <code>super()<\/code>. Terms and conditions still apply, such as, not accessing instance members of a derived class before execution of <code>super()<\/code> completes.<\/p>\n<p>I know you are wondering, why was this constraint added in the first place, how is this being resolved, does it change the internal JVM working, and the most important question &#8211; how can you benefit from this feature? I\u2019ll answer all these questions in this blog post.<\/p>\n<p>Let\u2019s start with an example.<\/p>\n<h2>Example 1 &#8211; validating values passed to super() in a derived class constructor<\/h2>\n<p>Imagine you need to create a class, say, <code>IndustryElement<\/code>, that extends class <code>Element<\/code>, which is defined as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class Element {\n   int atomicNumber;\n   Color color;\n\n   public Element(int atomicNumber, Color color) {\n       if (color == null)\n           throw new IllegalArgumentException(&quot;color is null&quot;);\n       this.atomicNumber = atomicNumber;\n       this.color = color;\n   }\n    \/\/ rest of the code\n}<\/pre>\n<p>The constructor of the class <code>Element<\/code> misses checking if the <code>atomicNumber<\/code> is in the range of 1-118 (all known elements have atomic numbers between 1 to 118). Often the source code of a base class is not accessible or open for modification. How would you validate the values passed to <code>atomicNumber<\/code> in the constructor of class <code>IndustryElement<\/code>?<\/p>\n<p>Until Java 21, no statements were allowed to execute before <code>super()<\/code>. Here\u2019s one of the ways we developers found a workaround by defining and calling static methods (static methods belong to a class and not to instances and can be executed before any instance of a class exists):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class IndustryElement extends Element{\n   private static final int MIN_ATOMIC_NUMBER = 1;\n   private static final int MAX_ATOMIC_NUMBER = 118;\n  \n   public IndustryElement(int atomicNumber, Color color) {\n       super(checkRange(atomicNumber, MIN_ATOMIC_NUMBER , MAX_ATOMIC_NUMBER), color);\n   }\n\n   private static int checkRange(int value, int lowerBound, int upperBound) {\n       if (value &lt; lowerBound || value &gt; upperBound)\n           throw new IllegalArgumentException(&quot;Atomic number out of range&quot;);\n       return value;\n   }\n}<\/pre>\n<p>Starting Java 22, you could inline the contents of your static method in the constructor for your derived class, as shown in the following gif:<\/p>\n<figure class=\"wp-block-image alignnone wp-image-16062\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/02\/inline-method-super.gif\" alt=\"\" \/><\/figure>\n<p>Here\u2019s the resultant code for your reference:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class IndustryElement extends Element{\n    private static final int MIN_ATOMIC_NUMBER = 1;\n    private static final int MAX_ATOMIC_NUMBER = 118;\n\n    public IndustryElement(int atomicNumber, Color color) {\n        if (atomicNumber &lt; MIN_ATOMIC_NUMBER || atomicNumber &gt; MAX_ATOMIC_NUMBER)\n            throw new IllegalArgumentException(&quot;Atomic number out of range&quot;);\n        super(atomicNumber, color);\n    }\n}<\/pre>\n<p>I know you have questions about the preceding code, but before we move forward, let me share the IntelliJ IDEA Project Configuration you\u2019d need for working with this feature in IntelliJ IDEA. If you are already familiar with it, skip the next section.<br \/>\n<H2>IntelliJ IDEA Configuration<\/H2><\/p>\n<p>Java 22 support is available in <a href=\"https:\/\/www.jetbrains.com\/idea\/nextversion\/\" target=\"_blank\" rel=\"noopener\">IntelliJ IDEA 2024.1 EAP<\/a>. The final release of this version is planned for March 2024.<\/p>\n<p>In your Project Settings, set the SDK to Java 22. For the language level, select \u201822 (Preview) &#8211; Statements before super(), string templates (2nd preview etc.)\u2019 on both the Project and Modules tab, as shown in the below settings screenshot:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/02\/idea-config.png\" alt=\"\" \/><\/figure>\n<p><H2>Why do you care about this feature?<\/H2><br \/>\nOften folks ask &#8211; isn\u2019t it better to enclose the validation logic in a separate method since it makes the code easier to read and understand? For example, in the previous example, wouldn\u2019t it be better to keep the validation logic in a separate method? My opinion &#8211; though it is a good question, it is not what this feature is trying to address.<\/p>\n<p>You could call the static method checkRange, before calling <code>super()<\/code> in the constructor of class <code>IndustryElement<\/code> as follows (the validation code is still delegated to another method):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class IndustryElement extends Element{\n    private static final int MIN_ATOMIC_NUMBER = 1;\n    private static final int MAX_ATOMIC_NUMBER = 118;\n\n    public IndustryElement(int atomicNumber, Color color) {\n        checkRange(atomicNumber, MIN_ATOMIC_NUMBER , MAX_ATOMIC_NUMBER);\n        super(atomicNumber, color);\n    }\n\n    private static int checkRange(int value, int lowerBound, int upperBound) {\n        if (value &lt; lowerBound || value &gt; upperBound)\n            throw new IllegalArgumentException(&quot;Atomic number out of range&quot;);\n        return value;\n    }\n}<\/pre>\n<p>I believe one of the real benefits here is that you have a choice. You are free to define code in the way you see it, that is, validate the arguments, if there are no issues, call the super class constructor.<\/p>\n<p>You might argue that one could call the super class constructor first, and validate its arguments later. I would never recommend it. It could even lead to technical debts. What if the validation code finds issues but logs an error message, instead of terminating the initialisation process? This is poor coding practice.<br \/>\n<H2>Why was execution of statements before super not allowed in the past?<\/H2><br \/>\nCompare a base class with a seed and the derived class with a plant that is formed using it. A seed needs to be fully formed, before any part of the plan or its processes can be accessed. Similarly, the constructor of a base class must execute completely, before any member variables or methods of a derived class can be called. So with this constraint, the Java platform was trying to protect the state of your instances.<\/p>\n<p>Also, if you do not explicitly call the constructor of a base class in a derived class constructor, the compiler inserts a call to the implicit, no-argument, base class constructor. In short, at least one base class constructor always gets executed for a derived class, whether you do that explicitly or not. This was the case since Java 1.0.<br \/>\n<H2>How does it work behind the scenes?<\/H2><br \/>\nThe language syntax has been relaxed but it doesn\u2019t change or impact the internal JVM instructions. There are no changes to the JVM instructions for this new feature because the order of execution of the constructors still remains unchanged &#8211; from base class to a derived class. Also, this feature still doesn&#8217;t allow you to use members of a derived class instance, until <code>super()<\/code> executes.<\/p>\n<p>Let\u2019s access and compare the instruction set of the constructor of class <code>IndustryElement<\/code>, before and after its modification &#8211; one that can execute statements before <code>super()<\/code> and the one that doesn\u2019t. To do so, use the following command:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\njavap -c IndustryElement.class<\/pre>\n<p>Here\u2019s the instruction set for the constructor that doesn\u2019t explicitly execute statements before <code>super()<\/code> and calls static methods to validate range of atomic number:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/02\/instructions-1.png\" alt=\"\" \/><\/figure>\n<p>Here\u2019s instruction set for the constructor that explicitly executes statements before super() to validate range of atomic number:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/02\/instructions-2.png\" alt=\"\" \/><\/figure>\n<p>The most important point to note here is that in both the cases, the constructor of the base class, that is, <code>Element<\/code> is called, after the execution of all other statements. Essentially, it means, you are still doing the same thing, it is just packaged in a way that makes things easier for you.<\/p>\n<p>I understand it is difficult to remember what each of these instruction codes means. Access the following link and search for the instruction code and following the above instructions set would be a breeze:<\/p>\n<p><a href=\"https:\/\/docs.oracle.com\/javase\/specs\/jvms\/se21\/html\/jvms-6.html#jvms-6.5.aload_n\" target=\"_blank\" rel=\"noopener\">https:\/\/docs.oracle.com\/javase\/specs\/jvms\/se21\/html\/jvms-6.html#jvms-6.5.aload_n<\/a><br \/>\n<H2>Can you execute \u2018any\u2019 statements before calling super()?<\/H2><\/p>\n<p>No. If the statements before <code>super()<\/code> try to access instance variables or execute methods of your derived class, your code won\u2019t compile. For example, if you change the static <code>checkRange()<\/code> method to an instance method, your code won\u2019t compile, as shown below:<\/p>\n<figure class=\"wp-block-image alignnone wp-image-16062\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/02\/instance-method-error.gif\" alt=\"\" \/><\/figure>\n<p>Before everythings gets boring, lets work with another example &#x1f642;<br \/>\n<H2>Example 2 &#8211; base class constructor parameters that use annotations for validations<\/H2><br \/>\nAssume that constructor of base class Element checks for a non null value being passed to its parameter via <code>@NotNull<\/code> annotation as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class Element {\n   int atomicNumber;\n   Color color;\n\n   public Element(int atomicNumber, @NotNull Color color) {\n       this.atomicNumber = atomicNumber;\n       this.color = color;\n   }\n    \/\/ rest of the code\n}<\/pre>\n<p>Annotations can give a false sense of security. Even though it might seem that this constructor wouldn\u2019t accept a null value for the parameter <code>color<\/code>, annotations can be disabled at runtime. So you must include code that checks for null safety in the derived class constructor, as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class IndustryElement extends Element{\n    private static final int MIN_ATOMIC_NUMBER = 1;\n    private static final int MAX_ATOMIC_NUMBER = 118;\n\n    public IndustryElement(int atomicNumber, Color color) {\n        Objects.requireNonNull(color, &quot;color can&#039;t be null&quot;);\n        if (atomicNumber &lt; MIN_ATOMIC_NUMBER || atomicNumber &gt; MAX_ATOMIC_NUMBER)\n            throw new IllegalArgumentException(&quot;Atomic number out of range&quot;);\n        \n        super(atomicNumber, color);\n    }\n}<\/pre>\n<p><H2>Example 3 &#8211; Transforming variable values received in a derived class constructor, before calling a base class constructor.<\/H2><\/p>\n<p>Our applications often receive data in multiple and varied formats, and may not be in the format we want to store or use that data. Easy solution-we transform the values to the ones that we require. However, handling the transformation is easier with methods other than the constructors.<\/p>\n<p>Imagine the constructor of the derived class <code>IndustryElement<\/code> receives the following JSON as a String value:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n{\n  &quot;atomicNumber&quot;: 6,\n  &quot;color&quot;: {\n    &quot;r&quot;: 255,\n    &quot;g&quot;: 128,\n    &quot;b&quot;: 0\n  }\n}<\/pre>\n<p>Or as a Comma Separated value, as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n6,255,128,0<\/pre>\n<p>There could be other formats too, say XML. The idea is that the data that is received by the constructor of a derived class can\u2019t be passed to the constructor of a base class in its original form. It must be transformed.<\/p>\n<p>Before this new feature that allowed statements before <code>super()<\/code>, you would have to define the constructor of the derived class <code>IndustryElement<\/code> as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n    public IndustryElement(String elementAsCSV) throws IOException {\n        super(getAtomicNumberFromCSV(elementAsCSV), getColorFromCSV(elementAsCSV));    \n    }\n\n    public static int getAtomicNumberFromCSV(String csv) {\n        Objects.requireNonNull(csv, &quot;CSV value can&#039;t be null&quot;);\n        String[] parts = csv.split(&quot;,&quot;);\n        int atomicNumber = Integer.parseInt(parts[0]);\n        return atomicNumber;\n    }\n    \n    public static Color getColorFromCSV(String csv) {\n        Objects.requireNonNull(csv, &quot;CSV value can&#039;t be null&quot;);\n        String[] parts = csv.split(&quot;,&quot;);\n        int r = Integer.parseInt(parts[1]);\n        int g = Integer.parseInt(parts[2]);\n        int b = Integer.parseInt(parts[3]);\n        return new Color(r, g, b);\n    }<\/pre>\n<p>With this new feature, you can simplify the preceding code as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n    public IndustryElement(String elementAsCSV) throws IOException {\n        Objects.requireNonNull(elementAsCSV, &quot;CSV value can&#039;t be null&quot;);\n        \n        String[] parts = elementAsCSV.split(&quot;,&quot;);\n        int atomicNumber = Integer.parseInt(parts[0]);\n        int r = Integer.parseInt(parts[1]);\n        int g = Integer.parseInt(parts[2]);\n        int b = Integer.parseInt(parts[3]);\n        \n        super(atomicNumber, new Color(r, g, b));\n    }<\/pre>\n<p><H2>Example 4 &#8211; Executing statements before this() in constructor of Records<\/H2><br \/>\nRecords, as we know can\u2019t extend other records or classes, because they implicitly extend <code>java.lang.Record<\/code> class. Records can benefit from this feature too by executing statements before calling <code>this()<\/code> in their constructors.<\/p>\n<p>For example, here\u2019s the code of a record <code>Palette2Colors<\/code> that represents a color palette with only two colors. For a specific business logic, the constructor uses either a brighter or a darker shade of the color value passed to its constructor:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic record Palette2Colors (String name,\n                              Color color1,\n                              Color color2) {\n\n    public Palette2Colors(String name, Color color1, Color color2) {\n        this.name = name.toUpperCase();\n        this.color1 = color1.brighter();\n        this.color2 = color2.darker();\n    }\n}<\/pre>\n<p>Imagine when you start using this record, you find multiple use cases where you have to pass an array of colors to this record instead of individual Color instances. You would prefer calling the other constructor since it has additional transformation logic.<\/p>\n<p>Here\u2019s how you might create this additional constructor (before Java 22):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n    public Palette2Colors(String name, Color[] colors) {\n        this(Objects.requireNonNull(name),\n             Objects.requireNonNull(colors, &quot;Color arr shouldn&#039;t be null&quot;)[0],\n             Objects.requireNonNull(colors[1]));\n    }<\/pre>\n<p>Though the preceding code is valid, this line of code <code>Objects.requireNonNull(colors, \"Color arr shouldn't be null\")[0]<\/code>, it is a bit difficult to read. Records can benefit from this feature too, and your could define the preceding constructor as follows (with Java 22):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n    public Palette2Colors(String name, Color[] colors) {\n        Objects.requireNonNull(name);\n        Objects.requireNonNull(colors, &quot;Color arr shouldn&#039;t be null&quot;);\n        Objects.requireNonNull(colors[0], &quot;Color[0] shouldn&#039;t be null&quot;);\n        Objects.requireNonNull(colors[1], &quot;Color arr shouldn&#039;t be null&quot;);\n        \n        this(name, colors[0], colors[1]);\n    }<\/pre>\n<p>You might be wondering you could have inlined the code defined in the other constructor in the preceding constructor as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n    public Palette2Colors(String name, Color[] colors) {\n        Objects.requireNonNull(name);\n        Objects.requireNonNull(colors, &quot;Color arr shouldn&#039;t be null&quot;);\n        Objects.requireNonNull(colors[0], &quot;Color[0] shouldn&#039;t be null&quot;);\n        Objects.requireNonNull(colors[1], &quot;Color arr shouldn&#039;t be null&quot;);\n        \n        this.name = name.toUpperCase();\n        this.color1 = color1.brighter();\n        this.color2 = color2.darker();\n    }<\/pre>\n<p>However, this would result in code repetition across constructors, which is never good. What happens if the business logic no longer needs to assign a lighter or darker shade of the color values passed as method arguments, and this logic is changed in just one constructor? Perfect place for bugs to hide!<br \/>\n<H2>Example 5 &#8211; Executing statements before this() in Enum constructors<\/H2><br \/>\nSimilar to a record, you could execute statements before this() in Enum constructors too. Here is an example of an enum, say, <code>BrightColor<\/code>, that defines two constructors:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic enum BrightColor {\n    MAGENTA(255, 0, 255),\n    CYAN(0, 255, 255),\n    YELLOW(255, 255, 0),\n    GREEN(Color.GREEN);\n\n    private int r;\n    private int g;\n    private int b;\n\n    private BrightColor(int r, int g, int b) {\n        this.r = r;\n        this.g = g;\n        this.b = b;\n    }\n\n    private BrightColor(Color color) {\n        Objects.requireNonNull(color);\n        this(color.getRed(), color.getGreen(), color.getBlue());\n    }\n    \/\/.. rest of the code\n}<\/pre>\n<p><H2>Example 6 &#8211; Executing statements before this() in classes<\/H2><br \/>\nStarting Java 22, you could also execute statements before <code>this()<\/code> in a class constructor, unless it doesn\u2019t call other instance members of the class. Below is an example:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class Voter{\n    String name;\n    int age;\n\n    public Voter(String name, int age) {\n        Objects.requireNonNull(name);\n        if (age &lt; 18) throw new IllegalArgumentException();\n        this.name = name;\n        this.age = age;\n    }\n\n    public Voter(String firstName, String lastName, int age) {\n        Objects.requireNonNull(firstName);\n        Objects.requireNonNull(lastName);\n        this(STR.&quot;\\{firstName} \\{lastName}&quot;, age);\n    }\n    \/\/ ..rest of the code\n}<\/pre>\n<p>The benefits of this approach is similar to what we covered in this blog post. The second constructor of class Voter, the one that accepts three method parameters can validate the parameters and then call <code>this()<\/code> which includes the validation and initialization code.<br \/>\n<H2>Preview Features<\/H2><br \/>\nStatements before super() is being introduced as a preview language feature in Java 22. 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 more 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 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 JDK mailing list (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.<\/p>\n<p><H2>Summary<\/H2><br \/>\nIn Java 22, the feature Statements before super() lets you execute code before calling <code>super()<\/code> in your derived class constructors, this() in your records or enums, so that you could validate the method parameters, or transform values, as required. This avoids creating workarounds like creating static methods and makes your code easier to read and understand.<\/p>\n<p>This feature doesn\u2019t change how constructors would operate now vs. how they operated earlier &#8211; the JVM instructions remain the same.<\/p>\n<p>The relaxation of this syntax rule starting Java 22 still ensures that <code>super()<\/code> completes before your access any members of a derived class. Your code wouldn\u2019t compile if you try otherwise.<\/p>\n","protected":false},"author":921,"featured_media":443395,"comment_status":"closed","ping_status":"closed","template":"","categories":[4759,5088],"tags":[5641,155,8418,8325],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea\/443113"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/users\/921"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/comments?post=443113"}],"version-history":[{"count":10,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea\/443113\/revisions"}],"predecessor-version":[{"id":446688,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea\/443113\/revisions\/446688"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/media\/443395"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/media?parent=443113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/categories?post=443113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/tags?post=443113"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/cross-post-tag?post=443113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}