{"id":448606,"date":"2024-03-08T12:33:32","date_gmt":"2024-03-08T11:33:32","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=448606"},"modified":"2024-03-08T12:33:37","modified_gmt":"2024-03-08T11:33:37","slug":"drop-the-baggage-use-_-for-unnamed-local-variables-and-patterns-in-java-22","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/fr\/idea\/2024\/03\/drop-the-baggage-use-_-for-unnamed-local-variables-and-patterns-in-java-22","title":{"rendered":"Drop the Baggage: Use &#8216;_&#8217; for Unnamed Local Variables and Patterns in Java 22"},"content":{"rendered":"<p>How would you feel if you tried to understand a code snippet, only to realize that some of the variables you were trying to make sense of, were never used? This could be due to the programming syntax constraints, or an oversight as a result of changes to a codebase over time. Would you like it if there was a way to mark such unused variables in the code, not via comments, but by using a language constraint (because real developers don\u2019t write comments)? Also, what happens if a maintainer uses these unused variables in a way they were not supposed to be? Errors, maybe?<\/p>\n<p>Starting Java 22, using <a href=\"https:\/\/openjdk.org\/jeps\/456\" target=\"_blank\" rel=\"noopener\">Unnamed Variables &amp; Patterns<\/a> you can mark unused local variables, patterns and pattern variables to be ignored, by replacing their names (or their types and names) with an underscore, that is, <code>_<\/code>. Since such variables and patterns no longer have a name, they are referred to as Unnamed variables and patterns. Ignoring unused variables would reduce the time and energy anyone would need to understand a code snippet. In the future, this could prevent errors :-). This language feature doesn\u2019t apply to instance or class variables.<\/p>\n<p>Are you wondering if replacing unused variables with <code>_<\/code> is always a good idea, or do they imply code smells and should you consider refactoring your codebase to remove them? Those are good questions to ask. I\u2019ll answer all these questions in the blog post, including how to spot unused local variables.<\/p>\n<p>Before diving deep into the details, let\u2019s take a quick look at one of the examples.<\/p>\n<h2>A quick example<\/h2>\n<p>The following gif gives a sneak peek into how an unused local variable, connection, is detected by IntelliJ IDEA, and could be replaced with an underscore, that is, <code>_<\/code>.<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" class=\"wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/03\/unused-variable-trailer.gif\" alt=\"\" \/><\/figure>\n<p>The modified code shown in the preceding gif makes it clear that the local variable defined in the try-with-resources statement is unused, making it concise and easier to understand.<\/p>\n<p>Before we discuss any further details, the next section includes basic IntelliJ IDEA Project Configuration you\u2019d need for working with this feature in IntelliJ IDEA. If you are already familiar with it, feel free to skip to the next section.<\/p>\n<h2>IntelliJ IDEA Configuration<\/h2>\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 &#8211; Unnamed variables and patterns\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\/03\/config1.png\" alt=\"\" \/><\/figure>\n<p>Let\u2019s start by talking about situations where an unused variable can\u2019t be deleted from your codebase for some reason.<\/p>\n<h2>Unused variables that can\u2019t be dropped<\/h2>\n<p>Local variables remain unused in some code snippets; but you might not be able to delete them. This could happen due to the language constraints or you might be using the side effect of those variables. In this section, I\u2019ll talk about the use cases where deleting an unused variable is either not possible or not recommended. In such cases, replacing them with an unnamed variable, that is, <code>_<\/code>, would be a good way to make it obvious and clear. Unnamed variables can\u2019t be used &#8211; they can\u2019t be passed to methods or assigned values.<\/p>\n<p>Let\u2019s talk about a sample code in which pattern variables are unused in a switch expression.<\/p>\n<h3>1. Unused Patterns and Pattern variables in switch constructs<\/h3>\n<p>Imagine you defined a sealed interface, say, <code>GeometricShape<\/code>, and records to represent shapes, such as, <code>Point<\/code>, <code>Line<\/code>, <code>Triangle<\/code>, <code>Square<\/code>, as shown in the following code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nsealed interface GeometricShape {}\nrecord Point   ( int x,\n                 int y)         implements GeometricShape { }\nrecord Line    ( Point start,\n                 Point end)     implements GeometricShape { }\nrecord Triangle( Point pointA,\n                 Point pointB,\n                 Point PointC)  implements GeometricShape { }\nrecord Square  ( Point pointA,\n                 Point pointB,\n                 Point PointC,\n                 Point pointD)  implements GeometricShape { }<\/pre>\n<p>Now assume you need a method that accepts an instance of <code>GeometricShape<\/code> and returns its area. Since <code>Point<\/code> and a <code>Line<\/code> are considered one-dimensional shapes, they wouldn\u2019t have an area. Following is one of the ways to define such method that calculates and returns area:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nint calcArea(GeometricShape figure) {\n    return switch (figure) {\n        case Point    (int x, int y)                        -&gt; 0;\n        case Line     (Point a, Point b)                    -&gt; 0;\n        case Triangle (Point a, Point b, Point c)           -&gt; areaTriangle(a, b, c);\n        case Square   (Point a, Point b, Point c, Point d)  -&gt; areaSquare  (a, b, c, d);\n    };\n}<\/pre>\n<p>In the previous example, the patterns <code>int x<\/code>, <code>int y<\/code>, <code>Point a<\/code> and <code>Point B<\/code> (for case label Line) remain unused as detected by IntelliJ IDEA. These could be replaced by an <code>_<\/code>. Also, since all the record components of the case Point remain unused, it could be replaced as <code>Point _<\/code>. This could also allow us to merge the first and second case labels. All of these steps are shown in the following gif:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" class=\"wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/03\/unused-pattern-variables1.gif\" alt=\"\" \/><\/figure>\n<p>Here\u2019s the modified code for your reference:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nint calcArea(GeometricShape figure) {\n    return switch (figure) {\n        case Point _, Line _                                -&gt; 0;  \n        case Triangle (Point a, Point b, Point c)           -&gt; areaTriangle(a, b, c);\n        case Square   (Point a, Point b, Point c, Point d)  -&gt; areaSquare  (a, b, c, d);\n    };\n}<\/pre>\n<p>In the preceding example, you can\u2019t delete the pattern variables even if they are unused. The code must include the cases when the instance passed to the method <code>calcArea()<\/code> is of type <code>Point<\/code> and <code>Line<\/code>, so that it could return 0 for them.<\/p>\n<h3>2. Unused Patterns or variables with nested records<\/h3>\n<p>This feature also comes in quite handy for nested records with multiple unused patterns or pattern variables, as demonstrated using the following example code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nrecord Name       (String fName, String lName) { }\nrecord PhoneNumber(String areaCode, String number) { }\nrecord Country    (String countryCode, String countryName) { }\nrecord Passenger  (Name name,\n                   PhoneNumber phoneNumber,\n                   Country from,\n                   Country destination) { }\n\npublic class GeoMaps {\n    boolean checkFirstNameAndCountryCodeAgain (Object obj) {\n        if (obj instanceof Passenger(Name (String fName, _),\n                                     _,\n                                     _,\n                                     Country (String countryCode, _) )) {\n\n            if (fName != null &amp;&amp; countryCode != null) {\n                return fName.startsWith(&quot;Simo&quot;) &amp;&amp; countryCode.equals(&quot;PRG&quot;);\n            }\n        }\n        return false;\n    }\n}<\/pre>\n<p>In the preceding code, since the if condition in the method <code>checkFirstNameAndCountryCodeAgain<\/code> uses only two pattern variables, others could be replaced using <code>_<\/code>; it reduced the noise in the code too.<\/p>\n<h3>3. Requirements change, but you need side effects of constructs like an enhanced for-loop<\/h3>\n<p>Below is an example of sample code that prints elements of an array to the console in an animated manner (you don\u2019t need to focus on the code logic. Just note that the local variable <code>num<\/code> is used within the for loop via a call to <code>System.out.println()<\/code>):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n    void animateArray() {\n        int[] numbers = {9, 7, 3, 8, 5, 2, 5};\n        int totalTimePerLine = 1000;\n        int count = 0;\n\n        \/\/ array element at first position is printed once, \n \/\/ second is printed twice and so on\n        for (int num : numbers) {\n            count++;\n\n\t     \/\/ each line takes a total of \u2018totalTimePerLine\u2019 to print\n            int delayPerNumber = totalTimePerLine \/ count;\n\n            for (int i = 0; i &lt; count; i++) { \n                System.out.print(num);    \n                try {\n                    Thread.sleep(delayPerNumber);  \n                } catch (InterruptedException e) {\n                    System.out.println(e);\n                }\n            }\n\n            System.out.println();\n        }\n    }<\/pre>\n<p>Imagine, after some time, the author of the previous code modifies it to print a fixed number, say, 0, instead of the array values. In this case, the code might no longer use the local loop variable <code>num<\/code> and it might change to the following (showing only the changed line of code for conciseness):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\n    void animateArray() {\n\t\/\/..code\n                System.out.print(0); \/\/ Remove the only usage of the variable num\n\t\/\/..code\n    }<\/pre>\n<p>Anyone reading the method <code>animateArray()<\/code> might not be able to know that at the first glance or read. However, the variable <code>num<\/code> can\u2019t be deleted, because it is defined as a loop variable in the enhanced for loop.<\/p>\n<p>Shortening the variable name to <code>n<\/code>, or using an implicit type, that is, <code>var<\/code>, instead of <code>num<\/code>, won\u2019t help much. A human must read a code snippet at least once to determine that a variable is unused. Time gone that would never come back!<\/p>\n<p>Also, it doesn\u2019t help much if you replace this enhanced for loop with the indexed loop, since the indexed loop variable wouldn\u2019t be used in the code too. In this case, the code is more interested in executing the code multiple times in a loop, rather than using the loop index. One of the simplest ways would be to announce that a variable is unused, so it could be ignored by folks reading this code.<\/p>\n<p>IDEs like IntelliJ IDEA were always able to determine this issue via their static code analysis (unused variables). With this new language feature, it can also suggest that you could replace an unused variable with an _. Here\u2019s a gif that shows this:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" class=\"wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/03\/unused-variable1.gif\" alt=\"\" \/><\/figure>\n<p>The next example talks about another approach to address the issue of an unused local variable.<\/p>\n<h3>4. Unused parameters in exception handlers; whose signature can\u2019t be modified<\/h3>\n<p>What happens when you use a method, say, <code>Thread.sleep()<\/code> that throws a checked exception, such as, <code>InterruptedException<\/code>? You must either handle the exception by enclosing the call to <code>Thread.sleep()<\/code> in an exception handler, or, add the <code>throws<\/code> clause to the method in which <code>Thread.sleep()<\/code> is called. In short, either you handle the exception yourself, or request the caller of this method to handle it.<\/p>\n<p>Let\u2019s consider handling an exception via a catch handler which receives an instance of the thrown exception. Though the information passed via the exception instance is useful, imagine a developer doesn\u2019t use it, and writes their code as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\ntry {\n    Thread.sleep(delayPerNumber);\n} catch (InterruptedException e) {\n    System.out.println(&quot;Sleep mode interrupted&quot;);\n}<\/pre>\n<p>In this case, the local variable <code>e<\/code> is unused. IntelliJ IDEA can determine it and suggest it to be replaced using <code>_<\/code>. You could also use the problems window to access the issues in your code base and apply the suggestions, as shown below:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" class=\"wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/03\/unused-variable2.gif\" alt=\"\" \/><\/figure>\n<h3>5. Unused auto-closeable resources in try-with-resources statements<\/h3>\n<p>It is common to see code similar to the following which checks DB connection parameters, database server availability, or network issues (for hosted databases) by establishing a connection to a database. It logs success or warning messages, but doesn\u2019t use the Connection instance, <code>connection<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nvoid checkConnection(String url, String user, String pwd) {\n    try (Connection connection = DriverManager.getConnection(url, user, pwd)) {\n        logger.info(STR.&quot;&quot;&quot;\n                        DB Connection successful\n                        URL = \\{url}\n                        usr = \\{user}\n                        pwd = \\{pwd}&quot;&quot;&quot;);\n    } catch (SQLException e) {\n        logger.warning(e.toString());\n    }\n}<\/pre>\n<p>The preceeding code is a good candidate to replace the local variable <code>connection<\/code> within the try-with-resources, with an underscore, as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nvoid checkConnection(String url, String user, String pwd) {\n    try (Connection _ = DriverManager.getConnection(url, user, pwd)) {\n        logger.info(STR.&quot;&quot;&quot;\n                        DB Connection successful\n                        URL = \\{url}\n                        usr = \\{user}\n                        pwd = \\{pwd}&quot;&quot;&quot;);\n    } catch (SQLException e) {\n        logger.warning(e.toString());\n    }\n}<\/pre>\n<p>With the examples in this section, I highlighted how to address the unused local variables, patterns and variables in your code, when they can&#8217;t be dropped from your code.<\/p>\n<p>You could apply a similar approach to other unused local variables that are defined within methods, including constructors, instance and static initialisers, if, for or while constructs, and passed as method parameters.<\/p>\n<p>Now, let\u2019s walk through a few examples where unused variables could imply a code smell.<\/p>\n<h2>When unused variables could be a code smell<\/h2>\n<p>You might need tests or experience to determine if the unused variables should be addressed in a way other than replacing their name using an underscore, that is, <code>_<\/code>.<\/p>\n<h3>1. Unused lambda parameter<\/h3>\n<p>Imagine you define the following code in which one of the lambda parameters, that is, x, is used and y is not:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nBiFunction&lt;Integer, Integer, Integer&gt; add = (x, y) -&gt; x + 0;<\/pre>\n<p>The previous code seems to be a code smell. The name of the method seems to suggest that it returns the sum of the values passed to it. In this case the corrective step should be to modify it as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\nBiFunction&lt;Integer, Integer, Integer&gt; add = (x, y) -&gt; x + y;<\/pre>\n<p>The preceding code is a simple example for demo purposes. When you refactor any code in your code, back them up using sufficient tests, so that the refactored code generates the same output.<\/p>\n<p>Also, the preceding code example doesn\u2019t imply that all unused method parameters are a code smell (as discussed previously in this blog post).<\/p>\n<h3>2. Methods with multiple responsibilities<\/h3>\n<p>As a good programming practice, a method should have a single responsibility. However, a method might not adhere to this practice. For instance, in the following code, the method <code>generateRandomNumbers()<\/code> prints a random number to the console, before returning it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class RandomNumber {\n    public static void main(String[] args) {\n        var randomNumber = generateRandomNumber();\n        System.out.println(randomNumber);\n    }\n    \n    public static int generateRandomNumber() {\n        int random = new Random().nextInt(100);\n        System.out.println(random);\n        return random;\n    }\n}\n&lt;code&gt;&lt;\/code&gt;<\/pre>\n<p>On execution, a user might see two outputs for the same random number, due to the two <code>println()<\/code> method calls &#8211; one in the method <code>generateRandomNumbers()<\/code> and the other in method <code>main()<\/code>. What if another developer deletes the call to the <code>println()<\/code> statement in method <code>main()<\/code>. In this case, the local variable <code>radomNumber<\/code> becomes unused, as follows:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic static void main(String[] args) {\n    var randomNumber = generateRandomNumber();\n}<\/pre>\n<p>Should you replace the name of variable randomNumber using an <code>_<\/code>? Nah! This looks like a code smell since the method <code>generateRandomNumber()<\/code> includes code to accomplish unrelated tasks &#8211; returning a random number and printing a random number to the console. A better solution would be to refactor your code, extracting the code to print a number to another method, so that <code>generateRandomNumber()<\/code> only generates a random number:<\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" class=\"wp-image-16062\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2024\/03\/unused-variable3.gif\" alt=\"\" \/><\/figure>\n<p>Here\u2019s the final code for your reference:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"\">\npublic class RandomNumber {\n    public static void main(String[] args) {\n        printNumberToConsole(generateRandomNumber());\n    }\n    \n    public static int generateRandomNumber() {\n        return new Random().nextInt(100);\n    }\n\n    private static void printNumberToConsole(int random) {\n        System.out.println(random);\n    }\n}<\/pre>\n<p>Having test methods to ensure that your method continues to serve their primary purpose is a good programming practice. I didn\u2019t include that part specifically since it would take the blog post in a tangent.<\/p>\n<p>In this blog post, I didn\u2019t cover an extensive list of use cases where an unused local variable could be a code smell.<\/p>\n<h2>Summary<\/h2>\n<p>As the name suggests, unnamed variables are local to a code construct, they don\u2019t have a name, and they are represented by using an underscore, that is, <code>_<\/code>. They can\u2019t be passed to methods, or used in expressions.<\/p>\n<p>By replacing unused local variables in a code base with <code>_<\/code> their intention is conveyed very clearly. It clearly communicates to anyone reading a code snippet that the variable is not used elsewhere. Until now, this intention could only be communicated via comments, which, unfortunately, all developers don\u2019t write.<\/p>\n<p>A production feature in Java 22, you could use this feature in your production code, without any fears of it being changed in one of the future versions.<\/p>\n","protected":false},"author":921,"featured_media":453564,"comment_status":"closed","ping_status":"closed","template":"","categories":[4759,5088],"tags":[3374,155,8418,8325],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/idea\/448606"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/921"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=448606"}],"version-history":[{"count":10,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/idea\/448606\/revisions"}],"predecessor-version":[{"id":458740,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/idea\/448606\/revisions\/458740"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media\/453564"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=448606"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=448606"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=448606"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=448606"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}