avatarWenqi Glantz

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

8046

Abstract

s-string">"something else"</span>; };</pre></div><h1 id="3689">Pattern Matching for instanceof</h1><p id="2784">This feature eliminates the need for explicit casts after a type check. The old way, we have to specifically cast the object after calling instanceof:</p><div id="f991"><pre><span class="hljs-keyword">if</span> (obj <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">String</span>) {
<span class="hljs-title class_">String</span> s = (<span class="hljs-title class_">String</span>) obj;
<span class="hljs-comment">// use s </span> }</pre></div><p id="4fa3">The new way, less verbose:</p><div id="8a47"><pre><span class="hljs-keyword">if</span> (obj <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">String</span> s) {
<span class="hljs-comment">// use s </span> }</pre></div><h1 id="8028">Text Blocks</h1><p id="1c64">Text containing multiple lines has always been notoriously ugly to express in Java. We are all familiar with such code snippet:</p><div id="3b09"><pre><span class="hljs-attribute">String</span> html = <span class="hljs-string">""</span>; <span class="hljs-attribute">html</span> += <span class="hljs-string">"<html>\n"</span>; <span class="hljs-attribute">html</span> += <span class="hljs-string">" <body>\n"</span>; <span class="hljs-attribute">html</span> += <span class="hljs-string">" <p>Hello, world</p>\n"</span>; <span class="hljs-attribute">html</span> += <span class="hljs-string">" </body>\n"</span>; <span class="hljs-attribute">html</span> += <span class="hljs-string">"</html>\n"</span>;</pre></div><p id="4746">Now we can use multi-line string literals called Text Blocks to make this situation more programmer-friendly:</p><div id="5bdf"><pre><span class="hljs-built_in">String</span> html = <span class="hljs-string">""" <html> <body> <p>Hello, world</p> </body> </html> """</span>;</pre></div><p id="5842">Text Blocks start with <code>"""</code> followed by a new line, and end with <code>"""</code>. So much cleaner! New lines and quotes without escaping!</p><h1 id="fa5c">Record Classes</h1><p id="b229">Record Classes introduce a new type declaration to the Java to define immutable data classes. Instead of the usual ceremony with private fields, getters and constructors, it allows us to use a <b>compact syntax. </b>Records can be thought of as <i>nominal tuples.</i></p><p id="01a0">Old way:</p><div id="3bce"><pre><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">class</span> <span class="hljs-symbol">Rectangle</span> { <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-built_in">double</span> length; <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-built_in">double</span> width;</pre></div><div id="9593"><pre><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Rectangle</span><span class="hljs-params">(<span class="hljs-type">double</span> length, <span class="hljs-type">double</span> width)</span> </span>{ <span class="hljs-keyword">this</span>.length = length; <span class="hljs-keyword">this</span>.width = width; }</pre></div><div id="3b70"><pre><span class="hljs-function"><span class="hljs-built_in">double</span> <span class="hljs-title">length</span>()</span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.length; } <span class="hljs-function"><span class="hljs-built_in">double</span> <span class="hljs-title">width</span>()</span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.width; }</pre></div><div id="4a6e"><pre><span class="hljs-comment">// Implementation of equals() and hashCode(), which specify</span> <span class="hljs-comment">// that two record objects are equal if they</span> <span class="hljs-comment">// are of the same type and contain equal field values.</span> <span class="hljs-keyword">public</span> <span class="hljs-built_in">boolean</span> <span class="hljs-keyword">equals</span><span class="hljs-params">...</span> <span class="hljs-keyword">public</span> int hashCode<span class="hljs-params">...</span></pre></div><div id="2287"><pre>// <span class="hljs-type">An</span> implementation <span class="hljs-keyword">of</span> toString() that returns a <span class="hljs-type">string</span> // representation <span class="hljs-keyword">of</span> all the record class's fields, // including their names. public <span class="hljs-type">String</span> toString() <span class="hljs-meta">{...}</span> }</pre></div><p id="21da">New way using Record class:</p><div id="f325"><pre><span class="hljs-function">record <span class="hljs-title">Rectangle</span><span class="hljs-params">(<span class="hljs-type">double</span> length, <span class="hljs-type">double</span> width)</span> </span>{ }</pre></div><p id="5570">A record class declaration consists of a name; optional type parameters (generic record declarations are supported); a header, which lists the “components” of the record; and a body. A record declaration specifies in a header a description of its contents; the appropriate accessors, constructor, <code>equals</code>, <code>hashCode</code>, and <code>toString</code> methods are created automatically. A record's fields are final because the class is intended to serve as a simple "data carrier".</p><p id="0598">For more information about record classes, see <a href="https://openjdk.java.net/jeps/395">JEP 395</a>.</p><h1 id="1e2a">Meaningful NPE</h1><p id="b4af">We are all used to seeing how NullPointerException gets thrown without clear indication of exactly which object is null, such as the example below.</p><div id="2c3a"><pre>Exception <span class="hljs-keyword">in</span> thread <span class="hljs-string">"main"</span> java<span class="hljs-selector-class">.lang</span><span class="hljs-selector-class">.NullPointerException</span>
at Unlucky<span class="hljs-selector-class">.method</span>(Unlucky<span class="hljs-selector-class">.java</span>:<span class="hljs-number">83</span>)</pre></div><p id="052d">Now we can see exactly why that NPE is thrown and how to fix it.</p><div id="6b9a"><pre>Exception in thread <span class="hljs-string">"main"</span> java.lang.NullPointerException:
Cannot<span class="hljs-built_in"> invoke </span><span class="hljs-string">"org.w3c.dom.Node.getChildNodes()"</span> because
the<span class="hljs-built_in"> return </span>value of <span class="hljs-string">"org.w3c.dom.NodeList.item(int)"</span> is null at Unlucky.method(Unlucky.java:83)</pre></div><h1 id="8eeb">Introduction of var</h1><p id="2c64">Initially introduced in Java 10, <code>var </code>keyword aims to improve developer experience by reducing the ceremony associated with writing Java code, especially with local variable declarations.</p><p id="faaf">Old way:</p><div id="e422"><pre>int length <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-comment">;</span> ... <span class="hljs-attribute">length</span> <span class="hljs-operator">=</span> str.length()<span class="hljs-comment">;</span></pre></div><p id="d4ad">New way with <code>var</code>:</p><div id="1bc5"><pre><span class="hljs-keyword">var</span> <span class="hljs-built_in">length</span> = str.<span class="hljs-built_in">length</span>();</pre></div><p id="5609">Notice: don’t confuse this <code>var </code>with JavaScript’s <code>var </code>keyword. This is not dynamic typing. The type of the declared variables is inferred at compile time. Using <code>var</code> instead of an explicit type makes this piece of code less verbose and easier to read.</p><h1 id="b081">New String Methods</h1><p id="0375">Java 11 and 12 introduced the fol

Options

lowing new String methods, pretty straightforward.</p><p id="79af"><code>indent</code></p><div id="c014"><pre><span class="hljs-built_in">String</span> <span class="hljs-built_in">str</span> = <span class="hljs-string">"This is a string."</span>; <span class="hljs-built_in">String</span> postIndent = <span class="hljs-built_in">str</span> .<span class="hljs-property">indent</span>(<span class="hljs-number">3</span>); <span class="hljs-comment">//" This is a string."</span></pre></div><p id="2d92"><code>transform:</code></p><div id="5ef4"><pre><span class="hljs-type">String</span> s = <span class="hljs-string">"hello"</span>.<span class="hljs-built_in">transform</span>(txt-> txt+ <span class="hljs-string">" world!"</span>); <span class="hljs-comment">//"hello world!"</span> <span class="hljs-type">int</span> result = <span class="hljs-string">"42"</span>.<span class="hljs-built_in">transform</span>(Integer::parseInt); <span class="hljs-comment">//42</span></pre></div><p id="ee42"><code>repeat:</code></p><div id="2ec9"><pre><span class="hljs-keyword">var</span> <span class="hljs-built_in">text</span> = <span class="hljs-string">"test "</span>; <span class="hljs-keyword">var</span> result = <span class="hljs-built_in">text</span>.repeat(<span class="hljs-number">2</span>); <span class="hljs-comment">// "test test "</span></pre></div><p id="2b3d"><code>isBlank:</code></p><div id="7302"><pre><span class="hljs-keyword">var</span> <span class="hljs-built_in">text</span> = <span class="hljs-string">" "</span>.isBlank(); <span class="hljs-comment">// true</span></pre></div><p id="0cf2"><code>strip:</code></p><div id="5e05"><pre>assertThat(<span class="hljs-string">" f oo "</span>.strip()).isEqualTo(<span class="hljs-string">"f oo"</span>)<span class="hljs-comment">;</span></pre></div><p id="cd25"><code>lines:</code></p><div id="2940"><pre><span class="hljs-string">"John\nSmith"</span><span class="hljs-string">.lines</span><span class="hljs-params">()</span><span class="hljs-string">.forEach</span><span class="hljs-params">(System.out::println)</span>;

<span class="hljs-string">//</span> John <span class="hljs-string">//</span> Smith</pre></div><h1 id="d85e">Collection Factory Methods</h1><p id="0bf9">Improvements to Collection factory methods were introduced in Java 9. If you haven’t had a chance to catch up, now is the time.</p><p id="7a73">Java is often criticized for its verbosity. Creating a small, unmodifiable collection (say, a <code>set</code>) involves constructing it, storing it in a local variable, and invoking <code>add()</code> on it several times, and then wrapping it. For example:</p><div id="b733"><pre><span class="hljs-keyword">Set</span><String> <span class="hljs-keyword">set</span> = <span class="hljs-built_in">new</span> HashSet<>(); <span class="hljs-keyword">set</span>.<span class="hljs-keyword">add</span>("a"); <span class="hljs-keyword">set</span>.<span class="hljs-keyword">add</span>("b"); <span class="hljs-keyword">set</span>.<span class="hljs-keyword">add</span>("c"); <span class="hljs-keyword">set</span> = Collections.unmodifiableSet(<span class="hljs-keyword">set</span>);</pre></div><p id="d75e">Now we can simply use the following to achieve same result:</p><div id="f81e"><pre><span class="hljs-keyword">Set</span><<span class="hljs-keyword">String</span>> <span class="hljs-keyword">set</span> = <span class="hljs-keyword">Set</span>.of(<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>, <span class="hljs-string">"c"</span>);</pre></div><p id="34f4">Same feature applies to Collections’ <code>List </code>and <code>Map</code>.</p><p id="b289">For a comprehensive list of JEPs from Java 8 through Java 17, refer to <a href="https://openjdk.java.net/jeps/0">https://openjdk.java.net/jeps/0</a>.</p><p id="bcf1">Feel free to check out some of my other stories on Medium:</p><div id="7916" class="link-block"> <a href="https://readmedium.com/spring-boot-microservices-coding-style-guidelines-and-best-practices-1dec229161c8"> <div> <div> <h2>Spring Boot Microservices Coding Style Guidelines and Best Practices</h2> <div><h3>Through working with Spring Boot microservices over the years, I have compiled a list of coding style guidelines and…</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*[email protected])"></div> </div> </div> </a> </div><div id="a7af" class="link-block"> <a href="https://readmedium.com/event-driven-programming-with-dapr-db96ac855a2d"> <div> <div> <h2>Event-Driven Programming with Dapr</h2> <div><h3>Deep Dive with Spring Boot Microservices</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*xS2xs3EAcWSrhq5_gETjRA.jpeg)"></div> </div> </div> </a> </div><div id="3ee0" class="link-block"> <a href="https://readmedium.com/consumer-driven-contract-testing-with-pact-f8a28a8a7c3c"> <div> <div> <h2>Consumer-Driven Contract Testing with Pact</h2> <div><h3>Deep Dive with Spring Boot Microservices</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*MD20-3yCEMgxXkALWsJ55w.jpeg)"></div> </div> </div> </a> </div><p id="7197">Happy coding! Happy crafting!</p><p id="3e6b">References:</p><div id="468a" class="link-block"> <a href="https://openjdk.java.net/jeps/0"> <div> <div> <h2>JEP 0: JEP Index</h2> <div><h3>This JEP is the index of all JDK Enhancement Proposals, known as JEPs. See JEP 1 for an overview of the JEP Process.</h3></div> <div><p>openjdk.java.net</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/)"></div> </div> </div> </a> </div><div id="d37d" class="link-block"> <a href="https://advancedweb.hu/a-categorized-list-of-all-java-and-jvm-features-since-jdk-8-to-17/"> <div> <div> <h2>A categorized list of all Java and JVM features since JDK 8 to 17</h2> <div><h3>Last updated on 2021/09/16 to include changes up to JDK 17. This article is also available in Chinese by Alex Tan…</h3></div> <div><p>advancedweb.hu</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*jtgb7Yoobz2qgUch)"></div> </div> </div> </a> </div><div id="2725" class="link-block"> <a href="https://docs.oracle.com/en/java/javase/16/language/records.html"> <div> <div> <h2>Java Language Updates</h2> <div><h3>Record classes, which are a special kind of class, help to model plain data aggregates with less ceremony than normal…</h3></div> <div><p>docs.oracle.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/)"></div> </div> </div> </a> </div><p id="563f"><a href="https://advancedweb.hu/new-language-features-since-java-8-to-17/#record-classes">https://advancedweb.hu/new-language-features-since-java-8-to-17/#record-classes</a></p></article></body>

Upgraded to the Shiny Java 17? Now What?

Photo by Wenqi at PA Grand Canyon

So your boss told you to upgrade your Spring Boot microservices to Java 17, you did it, all went well! From Java 8 to Java 17, a big jump! What changed? You wonder. What does this upgrade mean for us Java developers in our day to day programming life? Well, let’s take a closer look.

Released on September 15, 2021, Java 17 is the latest LTS (long-term support release) for the Java SE platform. From Java 8 to Java 17, there have been 194 JDK Enhancement Proposals (JEPs) introduced, each of which brings some improvement to the platform. Let’s pick a few to explore.

· Sealed Classes · Switch Expressions · Pattern Matching for Switch (Preview) · Pattern Matching for instanceof · Text Blocks · Record Classes · Meaningful NPE · Introduction of var · New String Methods · Collection Factory Methods

Sealed Classes

Sealed classes or interfaces can restrict which classes or interfaces can extend or implement them. It’s done so by using the sealed modifier, example below:

public abstract sealed class Tree
 permits Maple, Willow, Dogwood, Oak{ … }

Sealed class gives a tool to better design public APIs. It requires that the listed classes directly extend the sealed class. Compilation error will be thrown if any other classes try to extend the sealed class. Subclasses can also be sealed, which means that it’s possible to define whole hierarchies of fixed alternatives. Permitted classes must be located in the same package as the superclass.

For more information about sealed classes and interfaces, see JEP 409.

Switch Expressions

We’re all familiar with the good old Switch statements in Java:

switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        System.out.println(6);
        break;
    case TUESDAY:
        System.out.println(7);
        break;
    case THURSDAY:
    case SATURDAY:
        System.out.println(8);
        break;
    case WEDNESDAY:
        System.out.println(9);
        break;
}

Switch has got a facelift since Java 14! The same Switch statement above can be simplified as the following:

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

The example below shows Switch being used as an expression to populate a variable. Notice the default block and yield statement.

int numLetters = switch (day) {     
   case MONDAY, FRIDAY, SUNDAY -> 6;     
   case TUESDAY                -> 7;     
   default      -> {         
      String s = day.toString();         
      int result = s.length();         
      yield result;     } 
};

Pattern Matching for Switch (Preview)

The old way: switch was very limited, the cases could only test exact equality, and only for values of a few types: numbers, Enum types and Strings.

      char grade = 'A';

      switch(grade) {
         case 'A' :
            System.out.println("Excellent!"); 
            break;
         case 'B' :
         case 'C' :
            System.out.println("Well done");
            break;
         case 'D' :
            System.out.println("You passed");
         case 'F' :
            System.out.println("Better try again");
            break;
         default :
            System.out.println("Invalid grade");
      }

The new way: this preview feature enhances switch to work on any type and to match on more complex patterns, such as type pattern (Integer i), guard expression (i > 10), even null value.

Object o = 1234;  
String formatted = switch (o) {     
 case Integer i && i > 10 -> String.format("a large Integer %d", i);
 case Integer i           -> String.format("a small Integer %d", i);
 case null                -> System.out.println("Null"); 
 default                  -> "something else"; };

Pattern Matching for instanceof

This feature eliminates the need for explicit casts after a type check. The old way, we have to specifically cast the object after calling instanceof:

if (obj instanceof String) {     
    String s = (String) obj;     
    // use s 
}

The new way, less verbose:

if (obj instanceof String s) {     
    // use s 
}

Text Blocks

Text containing multiple lines has always been notoriously ugly to express in Java. We are all familiar with such code snippet:

String html = "";
html += "<html>\n";
html += "  <body>\n";
html += "    <p>Hello, world</p>\n";
html += "  </body>\n";
html += "</html>\n";

Now we can use multi-line string literals called Text Blocks to make this situation more programmer-friendly:

String html = """
          <html>
            <body>
              <p>Hello, world</p>
            </body>
          </html>
          """;

Text Blocks start with """ followed by a new line, and end with """. So much cleaner! New lines and quotes without escaping!

Record Classes

Record Classes introduce a new type declaration to the Java to define immutable data classes. Instead of the usual ceremony with private fields, getters and constructors, it allows us to use a compact syntax. Records can be thought of as nominal tuples.

Old way:

public final class Rectangle {
    private final double length;
    private final double width;
public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }
double length() { return this.length; }
    double width()  { return this.width; }
// Implementation of equals() and hashCode(), which specify
    // that two record objects are equal if they
    // are of the same type and contain equal field values.
    public boolean equals...
    public int hashCode...
// An implementation of toString() that returns a string
    // representation of all the record class's fields,
    // including their names.
    public String toString() {...}
}

New way using Record class:

record Rectangle(double length, double width) { }

A record class declaration consists of a name; optional type parameters (generic record declarations are supported); a header, which lists the “components” of the record; and a body. A record declaration specifies in a header a description of its contents; the appropriate accessors, constructor, equals, hashCode, and toString methods are created automatically. A record's fields are final because the class is intended to serve as a simple "data carrier".

For more information about record classes, see JEP 395.

Meaningful NPE

We are all used to seeing how NullPointerException gets thrown without clear indication of exactly which object is null, such as the example below.

Exception in thread "main" java.lang.NullPointerException         
at Unlucky.method(Unlucky.java:83)

Now we can see exactly why that NPE is thrown and how to fix it.

Exception in thread "main" java.lang.NullPointerException:   
Cannot invoke "org.w3c.dom.Node.getChildNodes()" because   
the return value of "org.w3c.dom.NodeList.item(int)" is null         at Unlucky.method(Unlucky.java:83)

Introduction of var

Initially introduced in Java 10, var keyword aims to improve developer experience by reducing the ceremony associated with writing Java code, especially with local variable declarations.

Old way:

int length = 0;
... 
length = str.length();

New way with var:

var length = str.length();

Notice: don’t confuse this var with JavaScript’s var keyword. This is not dynamic typing. The type of the declared variables is inferred at compile time. Using var instead of an explicit type makes this piece of code less verbose and easier to read.

New String Methods

Java 11 and 12 introduced the following new String methods, pretty straightforward.

indent

String str = "This is a string.";
String postIndent = str .indent(3); //"   This is a string."

transform:

String s = "hello".transform(txt-> txt+ " world!"); //"hello world!"
int result = "42".transform(Integer::parseInt); //42

repeat:

var text = "test ";
var result = text.repeat(2); // "test test "

isBlank:

var text = " ".isBlank(); // true

strip:

assertThat("  f oo  ".strip()).isEqualTo("f oo");

lines:

"John\nSmith".lines().forEach(System.out::println);

// John
// Smith

Collection Factory Methods

Improvements to Collection factory methods were introduced in Java 9. If you haven’t had a chance to catch up, now is the time.

Java is often criticized for its verbosity. Creating a small, unmodifiable collection (say, a set) involves constructing it, storing it in a local variable, and invoking add() on it several times, and then wrapping it. For example:

Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
set = Collections.unmodifiableSet(set);

Now we can simply use the following to achieve same result:

Set<String> set = Set.of("a", "b", "c");

Same feature applies to Collections’ List and Map.

For a comprehensive list of JEPs from Java 8 through Java 17, refer to https://openjdk.java.net/jeps/0.

Feel free to check out some of my other stories on Medium:

Happy coding! Happy crafting!

References:

https://advancedweb.hu/new-language-features-since-java-8-to-17/#record-classes

Java17
Sealed Classes
Record Classes
Switch Expression
Text Blocks
Recommended from ReadMedium