The Long-Term-Support (LTS) version of the Java language and runtime platform Java 17 was launched on September 14, 2021. Let's learn what's new in Java 17 and whether you should upgrade.

Many applications use older versions of Java, including the earlier LTS versions of Java: Java 11 and Java 8.

Why should businesses upgrade to the most current Java version? The upgrade to Java 17 requires effort, mainly to make the most of the new features and functions inside the JVM.

Many businesses use Docker and Docker images to switch to Java 17 easily with minimum effort and time. Developers can define their continuous integration/deployment (CI/CD) pipelines and run everything in Docker images. This won't impact other teams using older Java versions, as they can utilize old Docker images.

JAVA 17 Features

macOS and AArch64 Support

One of the critical JVM features added to this version is enhancing support for macOS on AArch64 architecture using JEP 391. It will support the latest series of processors (M1) Apple released with their computers in the last year.

It isn't necessarily a big deal for users on those platforms since some vendors have launched versions of JDK that support this architecture and even return support up from Java 8. However, the official seal of approval is essential to ensure future maintenance and support of the platform. In comparison, support for the Linux/AArch64 platform has been added to Java 9 and Windows/AArch64 in Java 16.

Sealed Classes

Sealed Classes is a feature that was introduced in Java 17. The sealed Classes feature has finished its trial phase and has become an official platform and language in Java 17. It permits a developer to specify the permissible sub-types that a type can have and prevent others from extending or implementing it in a way that is not intended.

Sealed classes also allow the compiler to generate errors at compile-time when you attempt to convert an unsealed type to a non-permitted subtype. Java 17 also brings a new rendering pipeline for AWT/Swing apps that run on macOS using the Apple Metal API instead of OpenGL. It has an improved API and enhanced features to generate random numbers.

Changes, Deletions, and Limitations in Java 17

Java 17 also brings several changes, deletions, and new limitations.

Encapsulation of JDK Internals

One change is the conclusion of the encapsulation process of JDK Internals. The first time this was introduced was within Java 9 and would give warnings during runtime when a user attempted to use reflection or similar to circumvent the usual restrictions on using internal APIs. Command-line arguments were also added to regulate this behavior.

From Java 9, various APIs have been created to offer a uniform way to do the most commonly-used tasks; users would utilize these APIs internally. With Java 16, the default was changed from a warning to disabling access to throwing an exception. However, it uses the command-line argument to alter the behavior.

With Java 17, the command-line argument is eliminated, and it is possible to deactivate this restriction. This means that all non-authorized access to those internal APIs is now protected.

Always-Strict Floating-Point Semantics

An additional “removal” can be described as the reintroduction of Always-Strict Floating Point semantics. Java 1.2 introduced modifications to the floating-point semantics default in Java that allows the JVM to trade in a tiny amount of precision in floating-point calculations to improve performance. In classes and methods where strict semantics had to be used, a strictfp keyword was added. Since then, various instruction set types have been introduced to the CPUs, making strict floating-point semantics be used without unnecessary cost. The need to implement a default or strict semantics has been eliminated.

Java 17 removes the previous default semantics, and all floating-point operations are executed strictly. The term strictfpis still present. However, it has no effect and causes a warning at compile time.

Ahead-of-Time (AOT) Compilation

Java 9 introduced ahead-of-time (AOT) compilation as an experimental feature that utilizes the Graal compiler, and a JIT code was written using Java. Java 10 made the Graal compiler usable as a JIT compiler in OpenJDK by incorporating the JVMCI interface. Since it was released, it has been a vast improvement. Graal compiler has seen tremendous advancements and has its JVM under the name of the GraalVM.

RMI Activation

RMI activation was eliminated in JEP 407 following its removal from Java 8 and finally deprecated and marked as a requirement for removal within Java 15. RMI Activation provided a method to enable distributed objects on-demand resources using RMI. However, it saw minimal usage, and a better alternative is available in the present. The remainder of RMI is unaffected by the elimination of the Activation portion.

Applet API Removal

Applet API has finally been designated for removal by JEP 398, initially removed within Java 9. The Applet API provided a way to integrate Java AWT/Swing controls into a web page within a browser. However, no modern browser can support this, which means that Applets have been essentially inaccessible over the last decade or so.

Security Manager

The most crucial deprecation is it's the security manager ( JEP 411). Security Manager has been in use for a while since Java 1.0. It was designed to restrict what Java could do locally on the machine, such as limiting access to networks, files, and other network resources. It also tries to sandbox code that is not trusted by blocking the reflection and specific APIs.

The end of Security Manager started in Java 12. A command-line argument was added to block the use of the security manager at runtime. The change made in Java 17 means that a runtime warning will be generated in the JVM when trying to set a Security Manager, either from the command line or dynamically at runtime.

Incubator and Preview Features

Many wondered whether Java 17 would have any preview and incubator features, considering that Java 17 was promoted to be a long-term supported version. Java 17 has two incubator modules and a preview feature!

Vector API

Vector API ( JEP 414) is currently in its second phase of the incubator. The API allows developers to define vector computation that the JIT compiler will then convert into the appropriate vector instruction supported by the CPU architecture that the JVM runs on (for instance, using those of the SSE or AVX instructions sets).

Before, developers had to use scalar functions or build native libraries that were specific to the platform. Implementing the Vector API in Java also provides a seamless fallback mechanism which was complicated in earlier versions.

The standardization of the Vector API enables the classes within the JDK to use it. Java Arrays mismatch() methods could be changed to be run on Java instead, eliminating the requirement to maintain and write multiple platforms-specific implementations within the JVM.

Foreign Function & Memory API

An additional incubator feature is called the Foreign Function & Memory API ( JEP 412). It is an evolution and merger of two other incubator modules of Java 16 that is The Foreign Linker API ( JEP 389) and Foreign-Memory API ( JEP 393). Both of them provide access to native memory and code by using statically-typed programming written in Java.

Pattern Matching for Switch

The final feature of the language preview included in Java 17 is the inclusion of Pattern Matching for Switch ( JEP 406). This language feature expands the switch expressions and statements according to type, similar to the syntax used through Pattern Matching (JEP 394), which became standard with Java 16.

In the past, if you wanted to perform different actions based on the dynamic nature of an object, you'd be required to construct an if-else chain using an instance of checks such as:

String type(Object o) {
  if (o instanceof List) {
    return "A List of things.";
  }
  else if (o instanceof Map) {
    return "A Map! It has keys and values.";
  }
  else if (o instanceof String) {
    return "This is a string.";
  }
  else {
    return "This is something else.";
  }
}

By combining the switch expression as well as the new pattern matching feature for switches, the process can be reduced to something similar to:

String type(Object o) {
  return switch (o) {
    case List l -> "A List of things.";
    case Map m -> "A Map! It has keys and values.";
    case String s -> "This is a string.";
    default -> "This is something else.";
  };
}

As you might have noticed, there's the declaration of a variable in the process of checking. Like the other variables in Pattern, the matching of instance indicates that this object was type-checked and cast and is available from the variable within its current area.

The preview function is another step towards pattern matching. The next step is to include the capability of deconstructing arrays and records.

Should You Upgrade to Java 17?

Yes, you must constantly upgrade to the most recent version, however not as soon as day one. The software and libraries you are using may not have been updated to include compatibility with Java 17, so you might need to wait for some time until it is done.

If you're stuck with an LTS version of Java like Java 8 or Java 11, there are numerous options within the language and within the JVM itself that require an upgrade up to Java 17. With it being a long-term maintenance release, there's a high chance that your production environment will eventually be updated to Java 17 too.

If you're beginning an entirely new project, or are in the process of getting your project ready and ready for Java 17, making the switch into Java 17 sooner rather than later is probably the most efficient choice since it reduces the costs of moving. This also allows the developers working on the project to utilize all the latest features and the ops side.

You can take advantage of the many improvements that have occurred over the past few years, such as improved support for containers running on Java, as well as new low-latency garbage collector implementations.