March 20, 2020

Java 14 New Features

Java 14 is announced officially. In this article, we will see the new API Updates, Language Features, Preview Features, and General Improvements introduced as part of Java 14.

You can find the documentation from the OpenJDK website for each point I mentioned below to get official information and a more in-depth understanding of the changes.

You can find the source code of this article here:
https://github.com/SaiUpadhyayula/java14-new-features

If you are a visual learner like me, you can check the video tutorial explaining the new features

Youtube Video for Java 14 new Features

Java API Updates

Removed API(s)

First, we will have a look at the API’s which are removed from Java 14. So if you are using the below API in your code, you have to remove those usages before moving to Java 14.

API(s) Deprecated for Removal

Now let’s look at some APIs that are Deprecated for Removal.

Added API(s)

These are the minor additions to Java API:

  • In the PrintStream class inside the java.io package, there is a new method called writeBytes(byte[] buff) which takes the incoming bytes to the method and writes it to the stream. Previously this was handled through write(byte[] buff, int offset, int length). You can check the API documentation here
  • There is a new annotation @Serial. This annotation type is intended to allow compile-time checking of serialization-related declarations, which is similar to the checking enabled by the @Override annotations when you are overriding a method. To enable these checks, you have to add -Xlint:serial flag to the compiler.
    You can read more about this annotation here.

These are the useful Java API updates in Java 14.

Helpful NullPointerExceptions

NullPointerExceptions need no introduction for Java developers, with Java 14 there is an improved description of NullPointerException. In this way, we can exactly know which variable is responsible for the NPE.

To enable this feature, we have to add the following arguments for the java compiler -XX:+ShowCodeDetailsInExceptionMessages. If you are using IntelliJ 2020.1 you can refer the below image to enable this feature.

IntelliJ setup for ShowCodeDetailsInExceptionMessage flag

Now let’s look at some code which produces NullPointerException

public class NullPointerExceptionDemo {

    public static void main(String[] args){

        String a = null;
        String b = a.toUpperCase();
        System.out.println(b);
    }
}

As you can see the above code obviously produces NPE, because we are trying to call toUpperCase() on a null reference. After enabling the -XX:+ShowCodeDetailsInExceptionMessages flag, here is how the NullPointerException error message looks like:

New NPE Message

You can see that the message clearly says – variable a is null

When we disable the flag, we can see the old NullPointerException

Old NPE Message

You can read the official documentation at – https://openjdk.java.net/jeps/358

Switch Expressions

Switch Expressions are first introduced as a preview feature in Java 12 and Java 13. Now in Java 14, switch expressions are a standard feature.

If you somehow missed reading about the Switch Expressions, you can now return values from a switch. Instead of using the return keyword we will use the keyword yield to avoid confusion, as in the switch expressions we will be using a code block under each case.

This is how we write switch statements:

package com.techie.demo;

public class SwitchExpressionDemo {
    public static void main(String[] args) {
        String sport = "Football";
        String bestPlayer = "";

        switch (sport) {
            case "Football":
                bestPlayer = "XXX";
                break;
            case "Tennis":
                bestPlayer = "YYY";
                break;
            case "Cricket":
                bestPlayer = "ZZZ";
                break;
            case "F1":
                bestPlayer = "AAA";
                break;
            default:
                bestPlayer = "Unknown";
        }

        System.out.println(bestPlayer);
    }
}

Now, this is how we write switch expressions:

package com.techie.demo;

public class SwitchExpressionDemo {
    public static void main(String[] args) {
        String sport = "Football";
        String bestPlayer = switch (sport) {
            case "Football":
                yield "XXX";
            case "Tennis":
                yield "YYY";
            case "Cricket":
                yield "ZZZ";
            case "F1":
                yield "AAA";
            default:
                yield "Unknown";
        };

        System.out.println(bestPlayer);
    }
}

We can make this much crisper and leaner by using an arrow function instead of yield keyword as this is a one-liner.

package com.techie.demo;

public class SwitchExpressionDemo {
    public static void main(String[] args) {
        String sport = "Football";
        String bestPlayer = switch (sport) {
            case "Football" -> "XXX";
            case "Tennis" -> "YYY";
            case "Cricket" -> "ZZZ";
            case "F1" -> "AAA";
            default -> "Unknown";
        };

        System.out.println(bestPlayer);
    }
}

Switch Expressions with Arrow function and Yield keyword.

package com.techie.demo;

public class SwitchExpressionDemo {
    public static void main(String[] args) {
        String sport = "Football";
        String bestPlayer = switch (sport) {
            case "Football" -> {
                System.out.println("Switch Case for Football");
                yield "XXX";
            }
            case "Tennis" -> "YYY";
            case "Cricket" -> "ZZZ";
            case "F1" -> "AAA";
            default -> "Unknown";
        };

        System.out.println(bestPlayer);
    }
}

You can read more about Switch Expressions here – https://openjdk.java.net/jeps/361

Preview Features

Java 14 introduced some Preview Features which are not yet finalized. Let’s have a look at what they are.
Note that, to try these new features you have to provide –enable-preview –release 14 flags to the Java Compiler. And for the JDK you can just provide –enable-preview flag.

This is how the java command looks in IntelliJ 2020.1 with Java 14 Preview Features enabled.

.jdks\openjdk-14\bin\java.exe --enable-preview "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 201.6487.11\lib\idea_rt.jar=56032:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 201.6487.11\bin" -Dfile.encoding=UTF-8 -classpath

Pattern Matching for instanceof

Before Java 14, when you are dealing with an Object we used the instanceof keyword to check the type of the object and if the check succeeds, we used to Cast it to our required type and perform any operations on our object.

public class PatternMatchingDemo {

    public static void main(String[] args){
        Object obj = "Java 14 is Here";
        if(obj instanceof String){
            String string = (String) obj;
            System.out.println(string.toUpperCase());
        }
    }
}

Now with Java 14, we can refactor the above code as below:

public class PatternMatchingDemo {

    public static void main(String[] args){
        Object obj = "Java 14 is Here";

        if(obj instanceof String s){
            System.out.println(s.toUpperCase());
        }
    }
}

You can observe that the cast is performed automatically and the value is bound to the variable s.

You can read more about this feature at – https://openjdk.java.net/jeps/305

Text Blocks (Second preview)

Text Blocks are not exactly a new feature in Java. It was already introduced as preview feature in Java 13. The goal is to declare multi-line strings in Java without using String concatenations.

public class TextBlocksDemo {

    public static void main(String[] args) {
        String html = "<html>\n" +
                "   <body>\n" +
                "      <p>Hello, World</p>\n" +
                "   </body>\n" +
                "</html>";

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

        String java14 = """
                    <html>
                        <body>\
                            <p>Hello, '\s' World</p>\
                        </body>
                    </html>""";

        System.out.println("----Before Java 13----");
        System.out.println(html);
        System.out.println("----From Java 13----");
        System.out.println(java13);
        System.out.println("----From Java 14----");
        System.out.println(java14);
    }
}

In the last String declaration, notice that we have a \ after the body and p tag. This suggests to Java Compiler to not consider the new line in the multi-line string. That’s why you can observe java14 prints the following output:

<html>
    <body>        <p>Hello, ' ' World</p>    </body>
</html>

Complete Output:

Multi String Output for different Java versions

You can read more about this feature at – https://openjdk.java.net/jeps/368

Packaging Tool (Incubator Phase)

This is not really a preview feature but a new tool introduced in Java 14 which is in Incubator Phase

The name of the tool is jpackage. The goal of this tool is to create platform-specific installers/packages instead of forcing the users to first install Java on the platform to run the JAR file.

If you are on:

  • Linux – you can generate a deb/rpm package
  • Mac – you can generate a pkg/dmg package
  • Windows – you can generate a msi/exe files

Note that to generate these packages, you have to use the JDK versions targeted to that specific platform.

ie. To generate an exe file you have to be on Windows and should use the Windows version of the JDK. The same applies to Linux and Mac.

Read more at – https://openjdk.java.net/jeps/343

Records

This is the feature I am most excited about in Java 14. It introduces a new type called a Record which is like an enhanced Data class. This can be typically used for Data Transfer Objects (DTOs), whose functionality is to act as a container for some data.

If you want to declare a Java class with some fields, normally the complete implementation will look something like below:

package model;

import java.math.BigDecimal;
import java.util.Objects;

public class Employee {
    private String firstName;
    private String lastName;
    private Integer age;
    private String address;
    private BigDecimal salary;

    public Employee(String firstName, String lastName, Integer age, String address, BigDecimal salary) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.address = address;
        this.salary = salary;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public BigDecimal getSalary() {
        return salary;
    }

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return firstName.equals(employee.firstName) &&
                lastName.equals(employee.lastName) &&
                age.equals(employee.age) &&
                address.equals(employee.address) &&
                salary.equals(employee.salary);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName, age, address, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", salary=" + salary +
                '}';
    }
}

You can have a look at the class structure in IntelliJ

Intellij Class Structure

That’s a lot of boilerplate code. There are some code generation libraries like Lombok which allows us to generate the majority of this code at compile time using Annotations.

Records turn the above boilerplate code to just 1 line like below:

package model;

import java.math.BigDecimal;

public record EmployeeRecord(String firstName, String lastName, Integer age, String address, BigDecimal salary) {
}

These acts like a restricted form of Data classes which are immutable and provides us with all the necessary methods which we discussed before like – equals/hashCode/toString

We can also get rid off the getter methods, Records provides us with accessor methods that are similar to the field name like – firstName(), lastName(), age(), etc.

Let’s look at the demo:

import model.Employee;
import model.EmployeeRecord;

import java.math.BigDecimal;

public class RecordsDemo {

    public static void main(String[] args) {
        EmployeeRecord employeeRecord = new EmployeeRecord("Keiser", "Soze",42,
                "New York", BigDecimal.valueOf(100000000));
        EmployeeRecord employeeRecord2 = new EmployeeRecord("Keiser", "Soze",42,
                "New York", BigDecimal.valueOf(100000000));
        EmployeeRecord employeeRecord3 = new EmployeeRecord("John", "Doe",42,
                "New York", BigDecimal.ZERO);

        System.out.println(employeeRecord.firstName());
        System.out.println(employeeRecord.lastName());

        System.out.println(employeeRecord3.firstName());
        System.out.println(employeeRecord3.lastName());

        System.out.println(employeeRecord.equals(employeeRecord2));  // true
        System.out.println(employeeRecord.equals(employeeRecord3));  // false

        System.out.println(employeeRecord.hashCode());
        System.out.println(employeeRecord2.hashCode());
        System.out.println(employeeRecord3.hashCode());


    }
}

Read more at – https://openjdk.java.net/jeps/359

General JVM Improvements

In this last section, let’s have a look at the JVM Improvements in Java 14.

G1 Garbage Collector Improvements

The default Garbage Collector since Java 9 is the G1 Garbage Collector. In Java 14, the G1 Garbage Collector has made NUMA-aware (Non-Uniform Memory Access).

The goal of this change is to improve the performance of the GC on large machines.

We can enable this by adding the -XX:+UseNUMA flag to the Java Compiler.

More details can be found here – https://openjdk.java.net/jeps/345

Z Garbage Collector Improvements (ZGC)

The second Garbage Collector change is for ZGC, which is introduced in Java 11. One of the changes here is to reduce the pause times under 10ms.

It was initially introduced only for Linux, but with Java 14 we also have ports for Mac and Windows.

Read more – https://openjdk.java.net/jeps/364 and https://openjdk.java.net/jeps/365

CMS Garbage Collector Removed

CMS Garbage Collector is deprecated as of Java 9, but from Java 14 this has been removed completely.

More Details – https://openjdk.java.net/jeps/363

Below are some low-level JVM improvements:

Java Flight Recorder Event Streaming

JDK Flight Recorder(JFR) is a tool that allows us to collect and profile data about running Java applications. With Java 14, JFR supports event streaming, that means now you can get real-time insights into the JVM without the need to dump the events and parse them manually.

Read more at – https://openjdk.java.net/jeps/349

Non-Volatile Mapped Byte Buffers

Read more at – https://openjdk.java.net/jeps/352

Foreign-Memory Access API (Incubator)

Read more at – https://openjdk.java.net/jeps/370

Conclusion

Alright, now you have seen almost all the features inside Java 14.

Don’t forget to have a look at all the Java Enhancement Proposals

You can have a look at this link – http://jdk.java.net/15/ to be updated with Java 15 which is in Early Acess.

If you like this article, you can have a look at my other articles here

About the author 

Sai Upadhyayula

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

Subscribe now to get the latest updates!