What’s New With Java 18 and What Do We Know About Java 19

by Hristina Nastevska

11 min read

Java 18 release date in March 2022, bringing some new enhancements and features, along with some preview features, which will be reviewed in this article.

After discussing the latest changes in Java 18, we'll mention the new releases in Java 19, which is set for general availability in September this year, following the six-month update on Java versioning that Oracle introduced.

Before leaning what's new in Java 18, it's a good reminder to check out the new features released in Java 17 by reading this article: The New Features in Java 17.

According to the official JDK 18 Oracle documentation, there are nine new features in Java 18:

  • UTF-8 by Default
  • Simple Web Server
  • Code Snippets in Java API Documentation
  • Reimplement Core Reflection with Method Handles
  • Vector API (Third Incubator)
  • Internet-Address Resolution SPI
  • Foreign Function & Memory API (Second Incubator)
  • Pattern Matching for switch (Second Preview)
  • Deprecate Finalization for Removal

UTF-8 by Default 

When writing or reading files and processing text, a charset can be supplied as a parameter to standard Java APIs. US-ASCII, UTF-8, and ISO-8859-1 are just a few of the supported charsets.

Standard Java APIs often utilize the default charset if no charset option is given. At startup, the JDK determines the default charset based on the runtime environment, which includes the operating system, the user's locale, and other considerations. That being said, it is evident that the default charset is not the same everywhere; therefore, this could cause issues even to some of the experienced developers when using APIs that use the default charset. 

The appropriate way to solve these potential issues is by setting the most universally used charset as a default; in this case, UTF-8. 

The main goals for this feature are to make Java programs more predictable and portable by using the default UTF-8 charset when it is not specified and standardizing the UTF-8 charset throughout SE Java APIs (with the exclusion of console I/O).

You can find more information in the official documentation about this feature: https://openjdk.java.net/jeps/400

Simple Web Server

This feature is more for educational purposes and focuses on making the JDK more approachable to developers by reducing their activation efforts by providing a command-line tool to start a simple web server for static files only. 

You can use this tool for prototyping, informal coding, and testing. This is a perfect tool for students and can be used when a local testing server is used to replicate a client-server setup in web development testing. You can also use it when static files are used as API stubs in a directory structure that mirrors RESTful URLs and contains dummy data in web service or application testing. Another application is when you need informal file browsing and sharing across systems, such as searching a distant server's directory from your local PC.

You can find more information in the official documentation about this feature: https://openjdk.java.net/jeps/408

Code Snippets in Java API Documentation

Documenting the implementation of the code is a critical aspect of the development cycle. This means the methods need to be very well explained for other developers to properly understand what the author had in mind when writing the code (method, methods).

Sometimes, we can achieve a better understanding by simply adding a code snippet; therefore, the @snippet tag for JavaDoc's Standard Doclet is introduced in Java 18 release notes.

In general, the main goals for this feature are to: 

  • improve IDE support for snippet creation and editing
  • enable contemporary style features like syntax highlighting and automated name-to-declaration linking
  • provide  API access to source code fragments to make their validation easier

Although the author is ultimately responsible for the accuracy, improved Javadoc and associated tools can make it easier to achieve the initial understanding of the logic. An example of a code snippet can be seen below:

/**
 * The following code shows how to use {@code Optional.isPresent}:
 * {@snippet :
 * if (optionalValue.isPresent()) {
 *     System.out.println("optionalValue: " + optionalValue.get());
 * }else{
	throw new NotFoundException();
 * }
 */

(taken from the official docs with some modification).

You can find more information in the official documentation about this feature: https://openjdk.java.net/jeps/413

Reimplement Core Reflection with Method Handles

The motivation behind this feature was to reduce the development and maintenance cost of java.lang.reflect and java.lang.invoke APIs by making the method handles the underlying mechanism for reflection. On top of java.lang.invoke method handles, java.lang.reflect.Method, Constructor, and Field are also being reimplemented. 

For calling methods and constructors, core reflection provides two internal techniques. For the initial few invocations of a certain reflective method or constructor object, it uses native methods in the HotSpot VM for quick startup. After a number of invocations, it develops bytecode for the reflective operation and utilizes it in subsequent invocations for higher peak performance.

Making any changes to the java.lang.reflect API is not the goal of this feature. This is purely a modification in the way it is implemented in order to achieve better maintenance and development costs. 

You can find more information in the official documentation about this feature: https://openjdk.java.net/jeps/416

Vector API (Third Incubator)

A vector computation is made up of a series of operations performed on vectors. A vector is composed of a (mostly) predefined series of scalar values that correlate to the number of hardware-defined vector lanes. 

When a binary operation is done to two vectors with the same number of lanes, the equivalent scalar operation is applied to the corresponding two scalar values from each vector for each lane. Single Instruction Multiple Data (SIMD) is a term used to describe this situation (SIMD).

Vector operations express a level of parallelism that allows more work to be done in a single CPU cycle, resulting in considerable performance improvements. If we have two vectors, each carrying a series of eight numbers (i.e., eight lanes), they can be joined using a single hardware instruction. The vector addition instruction makes eight integer additions on sixteen integers in the time it normally takes to conduct one integer addition on two integers.

The goal of these new Java 18 features is to have a clear and concise API, be platform-agnostic / CPU architecture agnostic, have a reliable runtime compilation and performance on x64 and AArch64 architectures, and a graceful degradation (at runtime, vector computation can't be properly described as a series of vector instructions due to not having architecture support for some of the required instructions; therefore, the implementation of the Vector API degrades gracefully but still functions.)

An example:

a.length  ==  b.length  ==  c.length

void scalarComputation(float[] a, float[] b, float[] c) {
   for (int i = 0; i < a.length; i++) {
        c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
   }
}

Equivalent vector computation:

static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;

void vectorComputation(float[] a, float[] b, float[] c) {
    int i = 0;
    int upperBound = SPECIES.loopBound(a.length);
    for (; i < upperBound; i += SPECIES.length()) {
        // FloatVector va, vb, vc;
        var va = FloatVector.fromArray(SPECIES, a, i);
        var vb = FloatVector.fromArray(SPECIES, b, i);
        var vc = va.mul(va)
                   .add(vb.mul(vb))
                   .neg();
        vc.intoArray(c, i);
    }
    for (; i < a.length; i++) {
        c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
    }
}

More simplified while still obtaining excellent performance without the scalar loop to handle the tail elements:

void vectorComputation(float[] a, float[] b, float[] c) {
    for (int i = 0; i < a.length; i += SPECIES.length()) {
        // VectorMask<Float>  m;
        var m = SPECIES.indexInRange(i, a.length);
        // FloatVector va, vb, vc;
        var va = FloatVector.fromArray(SPECIES, a, i, m);
        var vb = FloatVector.fromArray(SPECIES, b, i, m);
        var vc = va.mul(va)
                   .add(vb.mul(vb))
                   .neg();
        vc.intoArray(c, i, m);
    }
}

More about this code example and this feature can be found in the official documentation: https://openjdk.java.net/jeps/417

Internet-Address Resolution SPI

This feature's goal is pretty straightforward: creating a service-provider interface (SPI) for resolving host names and addresses in order java.net.InetAddress to use them instead of using the platform build-in resolver. 

The java.net.InetAddress API converts host names to IP addresses and the other way around. Currently, the API relies on the operating system's native resolver, which is commonly set up to utilize a mix of a local host file and the Domain Name System (DNS).

Let's note that it's not a goal for this feature to develop an alternate resolver to include in the JDK. 

The built-in resolver in the JDK will be utilized by default. Also, the SPI has no intention of supporting resolution operations other than those needed by the InetAddress API, and it's not aiming to specify asynchronous or non-blocking resolution APIs.

You can find more information in the official documentation about this feature: https://openjdk.java.net/jeps/418

Foreign Function & Memory API (Second Incubator)

The Java Platform has always provided a robust basis for library and application developers that want to communicate with platforms other than the JVM. Whether accessing external data (JDBC), invoking web services (HTTP client), serving remote clients (NIO channels), or communicating with local processes, Java APIs make non-Java resources accessible and reliable (Unix-domain sockets). 

That is one of the very useful capabilities that the Java Platform provides. However, unfortunately, Java developers still encounter substantial challenges when accessing a critical non-Java resource type: code and data located on the same computer as the JVM but outside of the Java runtime. 

This feature introduces an API to achieve just that by allowing Java applications to contact native libraries and handle native data without the brittleness and risk of JNI by effectively executing foreign functions and safely accessing foreign memory. 

Some of the changes include:

  • extended and newly added support for in-memory access var handles
  • boolean and MemoryAddress carriers
  • general API for MemoryAddress and MemorySegment interfaces
  • a simplified API for obtaining downcall method handles that no longer requires the provision of a MethodType argument
  • an API that makes managing temporal relationships across resource scopes easier
  • a new API for copying Java arrays into and out of memory segments 

The goals of this feature are ease of use, better performance, generality, and safety.

You can find more information in the official documentation about this feature: https://openjdk.java.net/jeps/419

Pattern Matching for switch (Second Preview)

We discussed this feature in a previous article, “Java 17 New Features”.

You can find more information in the official documentation: https://openjdk.java.net/jeps/420

Deprecate Finalization for Removal

Finalization will be deprecated and removed in a future release. For the time being, finalization is enabled by default; however, it may be eventually removed to ease early testing. It will be deactivated by default in a future release and ultimately eliminated. 

The motivation behind this removal was the many flaws of finalization that include:

  • Resource leaks
  • Unpredictable latency
  • Unconstrained behavior
  • Always enabled (needed or not)
  • Unspecified threading
  • Security vulnerabilities
  • Impacts performance
  • Unreliable execution 
  • Difficult programming model

Maintainers of libraries and applications that depend on finalization should consider using cleaners or the try-with-resources statement instead. 

You can find more information in the official documentation: https://openjdk.java.net/jeps/421

What Do We Know About Java 19

Java 19 is expected to be released for general availability on 2022/09/20. The Java 19 features that are listed in the official Oracle documentation are the following:

JEPs proposed to target JDK 19:       

  • Structured Concurrency (Incubator)     2022/06/02(review ends)

JEPs targeted to JDK 19, so far:

  • Record Patterns (Preview)
  • Linux/RISC-V Port
  • Foreign Function & Memory API (Preview)
  • Virtual Threads (Preview)
  • Vector API (Fourth Incubator)
  • Pattern Matching for switch (Third Preview)

Conclusion 

Java 18 has brought several features and enhancements, making the language more efficient and upgraded. Now, the default charset can be the same for everyone, and it will be the most used one - UTF-8. Beginners can now start learning the language without complications in setting up a web server, thanks to the simple web server feature that was introduced in this version. 

Documentation can be more descriptive with the @snippet tag, including writing code in the docs. There's a better implementation of core reflection with method handles, an introduction of the Vector API to express computations that reliably compile, and a creation of a service-provider interface (SPI) for resolving host names and addresses. 

In the next iteration of the language Java 19, which is still in the making, we may expect to see structured concurrency, Foreign Function & Memory API will still be tackled along with the Vector API and pattern matching for switch. Also, Linux/RICS-V Port will be available in the Java 19 programming tutorial.

FAQs

Q: How does the new Vector API improve computational performance in Java 18?
The new Vector API in Java 18 enhances computational performance by allowing developers to express vector computations that compile at runtime to optimal vector instructions on supported CPU architectures. This enables higher performance than equivalent scalar computations.
Q: What practical use cases exist for the Simple Web Server introduced in Java 18?
The Simple Web Server in Java 18 is practical for development, testing, and demonstration purposes. It allows developers to quickly serve and test static web content without setting up a full web server, facilitating rapid development cycles and simplifying the sharing of progress in web projects.
Q: How will the deprecation of finalization affect legacy Java codebases?
The deprecation of finalization in Java will require legacy codebases to migrate to alternative resource management mechanisms, like try-with-resources and cleaners, to handle resource release and cleanup efficiently and avoid potential memory leaks.
Hristina Nastevska
Hristina Nastevska
Java Engineer

Hristina is a senior software developer specializing in Java. In the last four years, she has been working as a Java backend developer in the banking domain industry. She's a Bachelor of Engineering in applied e-technologies.

Expertise
  • Java
  • Java
  • Spring Boot
  • Microservices
  • AngularJS
  • JavaScript
  • MySQL
  • HTML
  • +3

Ready to start?

Get in touch or schedule a call.