Skip to main content

New features in Java 15

We take a quick glance at the new features of the forthcoming Java 15, which is currently in the Initial Release Candidate phase, and is expected to be generally available in a month (15/9/2020). This is not a long-term support (LTS) release, which means that it can be used in production but it will be supported for six months only and until Java 16 is released. The latest Java LTS release was Java 11. 

At the moment of writing this blog post all features scheduled for the release (also known as JEPs, standing for JDK Enhancements Proposal) are marked as “Completed” or “Delivered”, so it safe to say that we are in the final straight.

We will look into the new production-ready features and also take a glance at preview and incubating features, which of course shouldn’t really be used in production, but are a good indication of what is being cooked for future Java versions. Finally, we are looking at both Java language and API changes and also new features of the JDK and the runtime environment. Even though it is not the goal of this post to extensively delve into each one of the features, we do try to give you a clear understanding of what each one of them is about and how it can be beneficial to an application.

Production ready Java language and SE API features

Text blocks (JEP 378)

A long awaited feature of Java, a text block is essentially a multi-line string literal. It avoids the need for most escape sequences, automatically formats the string in a predictable way, and gives the developer control over the format when desired. This is a feature that was introduced as a preview feature in Java 13 and has finally made it to production so it can now be used in production grade applications.

As an example, in past Java versions if we needed to define a long native SQL query in a JPA repository, we would have to write something like this:


String query = "SELECT \"EMP_ID\", \"LAST_NAME\" FROM \"EMPLOYEE_TB\"\n" +
               "WHERE \"CITY\" = 'EDINBURGH'\n" +
               "ORDER BY \"EMP_ID\", \"LAST_NAME\";\n";

This is now made a lot simpler and cleaner by using a text block (or a “two-dimensional block of text”, if you will):


String query = """
               SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
               WHERE "CITY" = 'EDINBURGH'
               ORDER BY "EMP_ID", "LAST_NAME";
               """;

Hidden classes (JEP 371)

Hidden classes are classes that cannot be used directly by other classes but instead are intended for use by frameworks that generate classes at run time and use them indirectly, via reflection. A hidden class may be defined as a member of an access control nest, and may be unloaded independently of other classes.

Therefore a hidden class can be used by a framework to hide some of its implementation details. Other classes cannot link to it and cannot discover it through reflection either. Furthermore, it allows extending an access control nest with non-discoverable classes. Other goals of this feature include:

  • Support aggressive unloading of non-discoverable classes, so that frameworks have the flexibility to define as many as they need.
  • Deprecate the non-standard API sun.misc.Unsafe::defineAnonymousClass, with the intent to deprecate it for removal in a future release.

It’s worth noting that the JEP explicitly states that this feature is not intended to change the Java programming language in any way.

Deprecate RMI Activation for Removal (JEP 385)

RMI Activation mechanism is deprecated and will be removed in the future. No other part of RMI will be deprecated.

RMI Activation is a part of RMI that has been optional since Java 8. Remote Object Activation is really an obsolete feature (introduced in Java 1.2) which allowed the developer to instantiate remote objects on demand using client requests and also allowed remote object references to persist across server crashes.

However, modern distributed systems have been based on web technology for at least the past decade. Concerns about traversing firewalls, filtering requests, authentication, and security have all been addressed in the web services space. Lazy instantiation of resources is handled by load balancers, orchestration, and containers. None of these mechanisms is present in the RMI Activation model for distributed systems. Furthermore there is evidence that very few applications nowadays use RMI activation at all, while it imposes a maintenance burden when it comes to keeping it as part of the Java platform. For all these reasons it’s unlikely that this feature will be missed.

Non - Production ready Java language and SE API features

Pattern Matching for instanceof (JEP 378)

This is the second preview of the feature that first made its appearance in Java 14. The instanceof operator is enhanced to reduce boilerplate code that is commonly present when using it. In a typical Java scenario we would write something like this:


if (obj instanceof String) {

    String s = (String) obj;
    // use s

}

This means that before writing any logic for our program we would need to do three things:

  1. Check if obj is a String, using the instanceOf operator,
  2. Cast obj to a String
  3. Assign the casted object to a String variable

This amend in the instanceof operator allows us to achieve all three in a single statement, and go on to write the more meaningful logic of our application:


if (obj instanceof String s) {

    // can use s here

}

 

Please note that the scope of a binding variable, unlike the scope of a local variable, is determined by the semantics of the containing expressions and statements. For example:


if (!(obj instanceof String s)) {

    // Cannot use binding variable s here

} else {

    // Use binding variable s here.

}

Sealed classes (JEP 360)

Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them. This feature allows the author of a class or interface to control which code is responsible for implementing it and also provides a more declarative way than access modifiers to restrict the use of a superclass. It also supports future directions in pattern matching by underpinning the exhaustive analysis of patterns. This feature does not change the final keyword in any way.

A class is sealed by applying the sealed modifier to its declaration. Then, after any extends and implements clauses, the permits clause specifies the classes that are permitted to extend the sealed class. For example, the following declaration of Shape specifies three permitted subclasses:


package com.example.geometry;

public sealed class Shape permits Circle, Rectangle, Square {
  // …
}

Records (JEP 384)

This is another feature that was introduced in Java 14 and this is its second preview. Records are classes that should be used as transparent carriers for immutable data. The purpose of a record is to declare that a small group of variables is to be regarded as a new kind of entity. A record declares its state (the group of variables) and commits to an API that matches that state.

The declaration of a record specifies a name, a header, and a body. The header lists the components of the record, which are the variables that make up its state. The list of components is sometimes referred to as the state description. For example:


record Point(int x, int y) { }

A record acquires many standard members automatically:

  • For each component in the header, two members: a public accessor method with the same name and return type as the component, and a private final field with the same type as the component;
  • A canonical constructor whose signature is the same as the header, and which assigns each private field to the corresponding argument from the new expression which instantiates the record;
  • equals and hashCode methods which say that two records are equal if they are of the same type and contain equal component values; and
  • A toString method that returns a string representation of all the record components along with their names.

To make it clear how more concise a record is compared to using a “regular” class just for transmitting immutable data, here is how the implementation of a class would look like for the record of the previous example:


class Point {
    private final int x;
    private final int y;
    
    Point(int x, int y) { 
        this.x = x;
        this.y = y;
    }
    
    int x() { return x; }
    int y() { return y; }
    
    public boolean equals(Object o) { 
        if (!(o instanceof Point)) return false;
        Point other = (Point) o;
        return other.x == x && other.y = y;
    }
    
    public int hashCode() {
        return Objects.hash(x, y);
    }
    
    public String toString() { 
        return String.format("Point[x=%d, y=%d]", x, y);
    }
}

 

Production ready JDK and Hotspot JVM features

The Z Garbage Collector is now a production feature (JEP 377)

The Z “Scalable Low-Latency” Garbage Collector was introduced in Java 11 and was an experimental feature until Java 14. The ZGC is supported on Linux/x86_64, Linux/aarch64, Windows and MacOS and the main new features and improvements it bears are:

  •  Concurrent class unloading
  •  Uncommitting unused memory
  •  Maximum heap size increased from 4TB to 16TB
  •  Minimum heap size decreased to 8MB
  •  -XX:SoftMaxHeapSize
  •  Support for the JFR leak profiler
  •  Support for class-data sharing
  •  Limited and discontiguous address spaces
  •  Support for placing the heap on NVRAM
  •  Improved NUMA awareness
  •  Multi-threaded heap pre-touching

It is important to note that G1 remains the default GC.

The Shenandoah GC is now also production ready (JEP 379)

Similarly to Z, Shenandoah was previously an experimental feature, introduced in JDK 12. Shenandoah is advertised as a “Low-Pause-Time” Garbage Collector which reduces GC pause times by performing more garbage collection work concurrently with the running Java program. It is also supported on all major platforms.

Shenandoah does the bulk of GC work concurrently, including the concurrent compaction, which means its pause times are no longer directly proportional to the size of the heap. Garbage collecting a 200 GB heap or a 2 GB heap should have the similar low pause behaviour.

Edwards-Curve Digital Signature Algorithm (JEP 339)

This is a new feature of the JDK API. EdDSA is a modern cryptographic signature scheme that has several advantages over the existing signature schemes and its implementation is expected to be consistently faster than the existing ECDSA implementation. This signature scheme is one of only three signature schemes that are allowed in TLS 1.3 and users will now be able to use it without relying on a third-party library.

Reimplement the Legacy DatagramSocket API (JEP 373)

The legacy implementations of the java.net.DatagramSocket and java.net.MulticastSocket APIs, used for UDP network communication will be replaced with more modern implementations that will also be easier to maintain. The legacy implementation dates back to JDK 1.0 in an era when IPv6 was still under development and apparently has grown very hard to maintain. It will continue being available by setting a new property jdk.net.usePlainDatagramSocketImpl to true (or no value) and will be marked as deprecated and eventually removed in a future version.

Removal of the Nashorn JavaScript Engine (JEP 372)

The Nashorn JavaScript script engine and APIs that were marked as deprecated since Java 11 will now be permanently removed.

The Nashorn JavaScript engine was introduced in JDK 8 as a complete implementation of the ECMAScript-262 5.1 standard in order to replace the Rhino scripting engine. With the rapid pace at which ECMAScript language constructs and APIs are adapted and modified,  Nashorn has become very challenging to maintain. There has also been little interest from developers to maintain Nashorn beyond JDK 14.

Biased Locking Disabled and Deprecated (JEP 374)

This is another “clean up” development, aiming to remove a legacy feature that no longer seems relevant in modern applications and also adds a burden “to making significant design changes within the synchronization subsystem”.

Biased locking is an optimisation technique used in the HotSpot Virtual Machine which attempts to avoid executing a compare-and-swap atomic operation when acquiring a monitor by assuming that the monitor remains owned by a given thread until a different thread tries to acquire it. The reason this is being removed is that apparently only legacy applications relying on the old Java Collections like Hashtable and Vector benefit from this optimisation, since these collections synchronise on every access. The removal is also a hint to developers to update their legacy applications and use more modern structures.

Removal of the Solaris and SPARC ports (JEP 381)

The source code and build support for the Solaris/SPARC, Solaris/x64, and Linux/SPARC ports have been removed. These ports were deprecated for removal in JDK 14.

Non - production ready JDK features

Foreign-Memory Access API (JEP 383)

The Foreign-Memory Access API was firstly introduced in Java 14 in late 2019 as an incubating API and in this second iteration it remains at the incubator stage. It is meant to be a safe, supported and efficient API that allows Java programs to safely and efficiently access memory outside of the Java heap.

The Foreign-Memory Access API is provided as an incubator module named jdk.incubator.foreign, in a package of the same name; it introduces three main abstractions: MemorySegment, MemoryAddress, and MemoryLayout:

  • A MemorySegment models a contiguous memory region with given spatial and temporal bounds.
  • A MemoryAddress models an address. There are generally two kinds of addresses: A checked address is an offset within a given memory segment, while an unchecked address is an address whose spatial and temporal bounds are unknown, as in the case of a memory address obtained (unsafely) from native code.
  • A MemoryLayout is a programmatic description of a memory segment's contents.

Summary

So this is what's new (and what's being removed) in the forthcoming Java 15. It will be interesting to see how many of the preview or incubation features will make it to production in the future but it’s certainly interesting to see Java keeping up with times and trying to address issues that have been annoying or at least puzzling developers in the past.

Here at CIVIC we have been using Java for almost two decades and have delivered a significant number of enterprise projects in the meantime, offering both development and hosting services. We always welcome new challenges so feel free to get in touch in case you need any help for your own project.