Java 17: New features overview

Java 17: Features overview
Java 17: Features overview

Java 17: Features overview

 

Java 17

 

Java 17 was released in September 2021. This is the latest release of LTS (Long Term Support). This means that this version will receive updated until 2029. An earlier version of LTS (Java 11) was released in September 2018, and between these two there were new releases every six months, but not covered by extended support.

Java was developed slowly to version 8. This appears to be due to a conservative and defensive strategy for introducing changes to the language. At a similar time to Java, the C# language was created, which was characterized by introducing additions on a regular basis to keep the language attractive and effective for programmers. Currently, the Java language is quite often extended with new functionalities but with the usual caution. We’ll cover the latest improvements between versions 11-17 in this article.

 

 

Switch modification

 

Switch in previous versions of Java looked like this:

switch przed aktualizacją

Source: Learn Java 17 with IntelliJ IDEA, https://www.youtube.com/watch?v=FP0V98S4l9w&ab_channel=Java

This function is used to consider different variants of a value. Depending on the value we want to convey the appropriate information to the user. Of course, we don’t have to use Switch for this task but the Switch syntax makes the code much more readable.

As you can see in the image above, there is a break command after each sequence. If we don’t locate this command in a specific case the executed code will go to the next sequence. Such a mechanism allowed to handle several cases with the same code. This style is also derived from the C language, where it referred to the assembly programming method (a low-level language specific to a given family of processors). Over the years, the style of programming has changed significantly and this use of the break command, or the lack of it, is less and less used. If someone forgets to add the break commands, the code may not work as intended. Therefore, an arrow notation was invented that implies break in arrows. This makes the Switch itself more readable to the user. This is important because there is less chance of making a mistake by accident. Below you can see how this record looks like.

switch w wersji strzałkowej

It is also possible to implement a return value, depending on the specific variant. This is advantageous because we can get a result that will be analysed further by the program. These features make the expression Switch much more convenient to use. So developers can write cleaner code that is easier to understand.

 

NullPointerExceptions

 

When programming in a language like Java, there is often a problem with no reference to an object. In earlier versions of the language, the system provided relatively accurate error information but this was not always sufficient to quickly identify the location where the error was causing the error. So far we have been able to find out that it exist at a specific line in the given file. This was problematic because there could be complicated code in one line, which made locating the mistake cumbersome. Before Java 14 the error information was as follows:

Exception in thread „main” java.lang.NullPointerEsception

pl.inero.ExamplesTest.NotMeaningFullNullPointerTest(ExamplesTest.java:155)

Java 14 introduces a facility that makes messages convey more precise information to programmers. This way, programmers can locate the error faster and go straight to repairing the code. An example of information about the lack of reference to the object in, after the implementation of this improvement, looks like this:

Cannot invoke „String.toUpperCase()” because „testOne.company” is null

 

 

Improvement to String constant in Java 17

 

Java 15 introduces so-called Text Blocks. Thanks to them, entering multi-line fixed string is much more convenient. Before Java 15 you had to enter multi-line constant strings on one line and save newlines as /n. The only way to write a multi-line constant in the code on many lines (for readability) was to divide it into smaller fragments connected by the + operator.

In java 15 start a block of text with three quotation marks “ “ “ and a new line. All subsequent lines up to the next sequence of three quotation marks “ “ “ will be the contents of the constant. It is not necessary to add newlines with /n. In addition, the indents will be left-aligned as much as possible.

Multi-line String constant before Java 15:

String beforeTextBlock = "SELECT some_id, COUNT(*)\n" + 
        "FROM (\n" + 
        "         select da.some_date dd, d.id some_id\n" + 
        "         from some_aud da\n" + 
        "     ) as subq\n" + 
        "GROUP BY some_id\n" + 
        "\t\tDouble \"Double \"quotes\"\" test\n";

Equivalent multi-line constant String after the introduction of Java 15:

String withTextBlock = """ 
        SELECT some_id, COUNT(*) 
        FROM ( 
                 select da.some_date dd, d.id some_id 
                 from some_aud da 
             ) as subq 
        GROUP BY some_id 
        \t\tDouble „Double „quotes”” test 
        """;

 

Pattern Matching

 

Java 16 introduced pattern matching extension for instanceof operator. Before introducing this functionality, after successfully verifying the class of an object, in order to use its properties, you had to manually cast the object to the verified type. It looked like this:

if(someObject instanceof String) { 
    String someString = (String) someObject; 
    //Operacje na zmiennej someString 
}

However, thanks to pattern matching for instanceof we are able to express the program logic more clearly. Below you can see what the code looks like:

if(someObject instanceof String someString) { 
    //Operacje na zmiennej someString 
}

Thanks to this update, we can check if an object is an instance of a given class and define a new variable that we assign to the Spring type with one notation:

someObject instanceof String someString

This provision:

  1. Checks if someObject is an instance of the String class,
  2. cast someObject to the String type,
  3. and assigns a String object to the variable someString.

 

 

Records

 

Records have been introduced in Java 16. They allow easier creation of classes for data models. Records automatically implement equals(), hashCode(), toString() and field accessors.

Thanks to this, instead of describing the class with data like this:

public final class NoRecordClass { 
    private final String title; 
    private final String author; 

    public NoRecordClass(String title, String author, String isbn) { 
        this.title = title; 
        this.author = author; 
    } 

    public String getTitle() { 
        return title; 
    } 

    public String getAuthor() { 
        return author; 
    } 

    @Override 
    public boolean equals(Object o) { 
        if (this == o) return true; 
        if (o == null || getClass() != o.getClass()) return false; 
        NoRecordClass book = (NoRecordClass) o; 
        return Objects.equals(title, book.title) 
                && Objects.equals(author, book.author); 
    } 

    @Override 
    public int hashCode() { 
        return Objects.hash(title, author); 
    } 
}

We can use such a short notation:

public record RecordExample(String title, String author) { 
}

Note that for a Java 16 record the accessors differ from those shown in the previous sample – to get the value corresponding to the title field in NoRecordClass use the getTitle() method. However, for the RecordExample class use the title() method, that was generated at compile time. As you can see, the difference is that the accessors generated for the record do not have the prefix get. For this reason, the records do not follow the Java Beans encoding convention. According to the JEP 395 document, the records are primarily to play the role of the so-called named tuple rather than the easier creation of immutable Java Beans. The difference is rather subtle but it can make it incompatible with some older libraries.

 

 

Sealed modifier in Java 17

 

The last functionality we describe is especially useful for library creators. It is used to control what classes/interfaces can inherit or implement a given class/interface. Thanks to this, no unauthorized person can connect his class to our library. Below you will find what such a record looks like:

public sealed interface SealedInterface 
        permits ImplementationNo1, 
                ImplementationNo2, 
                ImplementationNo3 { 
    int getNumber(); 
    String getText(); 
    List<String> getStrings(); 
}

 

 

Summary

 

Java 17 doesn’t actually provide any spectacular modifications. In fact, it stabilizes the changes that occurred during version 12-16. However, we can point out a few fixes that will definitely improve the work of programmers. This is primarily about: records, switch, pattern matching, sealed modifier or text blocks. Java 17 is definitely a big step forward, mainly because it is an LTS version, Thanks to this, developers will be able to count on ongoing support for the functionalities mentioned in this article.

Inero Software provides knowledge and expertise on how to successfully use cutting edge technologies and data to shape corporate digital products of the future.

In the blog post section you will find other articles about IT systems and more!

Consulted by: Tomasz Bieliński.