JAVA-RELEASE/JAVA-17

Java 17[LTS]: Exploring New Features and Enhancements

This article covers features of Java 17 with code examples

Pravinkumar Singh
6 min readJun 8, 2023

Java 17, released in September 2021, is the latest long-term support (LTS) version of Java. It brings a host of new features, enhancements, and improvements to the language and platform. In this article, we’ll explore some of the most exciting additions to Java 17 in a casual and easy-to-understand manner, along with code examples to help you get started.

Sealed Classes (JEP 409)

Sealed classes are a new feature in Java 17 that allows you to restrict the subclasses of a class or interface. This can be useful when you want to have a limited set of subclasses for a specific class hierarchy. Sealed classes improve maintainability, readability, and can enable more exhaustive pattern matching in the future.

To create a sealed class, use the `sealed` keyword and specify the permitted subclasses using the `permits` keyword:

public sealed class Shape permits Circle, Rectangle, Triangle {
// ...
}

public final class Circle extends Shape {
// ...
}

public final class Rectangle extends Shape {
// ...
}

public non-sealed class Triangle extends Shape {
// ...
}

In the example above, `Shape` is a sealed class that allows only `Circle`, `Rectangle`, and `Triangle` as subclasses. Notice the use of `final` and `non-sealed` keywords in the subclasses. A sealed class’s permitted subclasses must be marked as either `final`, `sealed`, or `non-sealed`.

Pattern Matching for Switch(JEP 408)

Pattern Matching for `switch` is a new feature in Java 17 that simplifies the common coding patterns and allows developers to express them more concisely and safely. It combines the existing `switch` statement with pattern matching and a new simplified form of the `switch` expression.

Here’s an example of how pattern matching for `switch` can simplify code:

public String formatDayOfWeek(DayOfWeek dayOfWeek) {
return switch (dayOfWeek) {
case MONDAY -> "Monday";
case TUESDAY -> "Tuesday";
case WEDNESDAY -> "Wednesday";
case THURSDAY -> "Thursday";
case FRIDAY -> "Friday";
case SATURDAY -> "Saturday";
case SUNDAY -> "Sunday";
};
}

In this example, the new `switch` expression allows us to directly return the result of each case, making the code more concise and readable.

Enhanced Pseudo-Random Number Generators (JEP 356)

Java 17 introduces new interfaces and implementations for random number generation, making it easier to use and extend various random number generation algorithms. The new `java.util.random` package provides the `RandomGenerator` interface, which is the base interface for all random number generators.

Here’s an example of how to use the new random number generators:

import java.util.random.*;

public class RandomDemo {
public static void main(String[] args) {
RandomGenerator rng = RandomGeneratorFactory.of("L64X128MixRandom").create();
System.out.println("Random int: " + rng.nextInt());
System.out.println("Random double: " + rng.nextDouble());
}
}

In this example, we create a random number generator using the `L64X128MixRandom` algorithm and generate random integers and doubles.

Foreign Function & Memory API (Incubator) (JEP 412)

Java 17 introduces an incubating Foreign Function & Memory API, which provides a pure Java API for calling native code and working with native memory. This API aims to provide a safer and more efficient alternative to the Java Native Interface (JNI).

Here’s an example of how to use the Foreign Function & Memory API to call a C function:

import jdk.incubator.foreign.*;
import jdk.incubator.foreign.FunctionDescriptor.*;
import static jdk.incubator.foreign.CLinker.*;

public class ForeignFunctionDemo {
public static void main(String[] args) {
try (var scope = ResourceScope.newConfinedScope()) {
var path = System.mapLibraryName("myclibrary");
var lib = LibraryLookup.ofPath(Path.of(path));
var strlenFunc = lib.lookup("strlen").get();

var strlenDescriptor = FunctionDescriptor.of(C_INT, C_POINTER);
var strlen = CLinker.getInstance().downcallHandle(strlenFunc, strlenDescriptor, MethodType.methodType(int.class, MemoryAddress.class));

var input = "Hello, World!";
var cString = CLinker.toCString(input, scope);

int length = (int) strlen.invokeExact(cString.address());
System.out.println("Length: " + length);
} catch (Throwable e) {
e.printStackTrace();
}
}
}

In this example, we use the Foreign Function & Memory API to call the `strlen` function from a C library. We first load the library, look up the `strlen` function, and create a `FunctionDescriptor` for it. Then, we obtain a method handle for the function using `CLinker.downcallHandle()`. Finally, we convert a Java string to a C string and call the `strlen` function using the method handle.

Please note that this API is still in incubation and may change in future releases.

Deprecate the Security Manager for Removal (JEP 411)

Java 17 deprecates the Security Manager for future removal. The Security Manager has been a core component of the Java platform since its inception, but it has become less relevant over time due to the introduction of new security mechanisms like the Java Module System.

Although the Security Manager is still available in Java 17, it is marked for future removal. Developers should start migrating their applications to alternative security mechanisms.

macOS/AArch64 Port (JEP 391)

Java 17 introduces a macOS/AArch64 port, adding support for Apple’s ARM-based processors (Apple M1 chip). This allows developers to run Java applications on macOS devices with ARM processors.

New macOS Rendering Pipeline (JEP 382)

Java 17 introduces a new rendering pipeline for macOS called Metal. It replaces the existing pipeline, which was based on the deprecated OpenGL framework. The new Metal pipeline provides better performance and compatibility with future macOS releases.

Restore Always-Strict Floating-Point Semantics (JEP 306)

In earlier Java versions, the strict floating-point semantics specified by the Java Language Specification were not strictly followed due to performance reasons. Java 17 changes that by ensuring strict floating-point semantics consistently, thereby eliminating unpredictable numerical results in some scenarios and enhancing the overall precision of floating-point operations.

Deprecate the Applet API for Removal (JEP 398)

With the evolution of web technologies, Applets are on the verge of becoming obsolete. Given the increasing shift to modern web standards, Java 17 marks the Applet API, part of java.awt and javax.swing packages, as deprecated so that it can be removed in future versions. Developers should move towards Java Web Start or installable applications as alternatives.

Strongly Encapsulate JDK Internals (JEP 403)

Java 17 improves security by restricting unauthorized access to internal JDK elements. It provides an enhanced access barrier for internal elements that are not part of the standard APIs, thereby ensuring better application security.

Remove RMI Activation (JEP 407)

Java 17 removes the RMI Activation System, a part of Java RMI (Remote Method Invocation) that was deprecated for removal in Java 15. This is due to its outdated design, which includes running untrusted code with security manager protection.

Remove the Experimental AOT and JIT Compiler (JEP 410)

Java 11 introduced an experimental feature — the Ahead-of-Time (AOT) and Just-in-Time (JIT) compiler, based on Graal compiler. This has been removed in Java 17. Users who require AOT or JVMCI-based JIT compilation can use GraalVM instead.

Vector API (Second Incubator) (JEP 414)

The Vector API moves into its second round as an incubator in Java 17. Vector operations provide a way to perform specific tasks simultaneously over large amounts of data, demonstrating significant speed-up for certain computations, an operation otherwise referred to as SIMD (Single Instruction, Multiple Data).

import jdk.incubator.vector.*;

public class VectorExample {
public static void main(String[] args) {

var a = FloatVector
.fromArray(VectorSpecies.of(float.class, VectorShape.S_128_BIT), new float[]{1, 2, 3, 4}, 0);
var b = FloatVector
.fromArray(VectorSpecies.of(float.class, VectorShape.S_128_BIT), new float[]{5, 6, 7, 8}, 0);

var c = a.add(b); // Vector addition

float[] result = new float[VectorShape.S_128_BIT.length()];
c.intoArray(result, 0);

//Printing results
for (float v : result) {
System.out.println(v);
}
}
}

Context-Specific Deserialization Filters (JEP 415)

Deserialization of untrusted data is a known vulnerability. To mitigate this, Java 17 introduces context-specific deserialization filters. This feature allows a filter to be specified for each deserialization operation, providing contextual and finer control to filter out malicious data objects.

ObjectInputFilter filter = ...
ObjectInputStream stream = new ObjectInputStream(inputStream);
stream.setObjectInputFilter(filter);

Conclusion

Java 17 brings a variety of new features and enhancements that improve the language and platform. With additions like sealed classes, pattern matching for `switch`, new random number generators, and the macOS/AArch64 port, Java continues to evolve and adapt to modern development needs. As Java 17 is an LTS release, it’s a great time to explore these new features and consider upgrading your projects to take advantage of the latest advancements in the Java ecosystem.

Peace!

Related reads : java-release

--

--