Java 17 Features you must know

Vikas Taank
4 min readDec 15, 2023

--

Java 17 was released in September 2021, is a long-term support (LTS) release and brought several important new features and enhancements to the library. Some of these are more developer-focused, improving the language and the JDK, while others are more internal, enhancing the JVM, security, and performance. In this article I want to discuss the most significant features:

Sealed Classes:Key Concepts of Sealed Classes

Sealed classes restrict which other classes may extend them. For a Class to be sealed you need to define which all classes are allowed to extend that class.

Permitted subclasses are defined using Permit clause and only this classes can extend the sealed class.

The subclasses of a sealed class can be either final, sealed, or non-sealed:

  • Final: Cannot be subclassed further.
  • Sealed: Can be subclassed but must also specify its permitted subclasses.
  • Non-sealed: Can be subclassed by any class (essentially opting out of the sealing contract).

Interfaces: Sealed classes can also be interfaces. The same rules apply: you must explicitly specify which interfaces or classes are permitted to extend or implement the sealed interface.

Example of Sealed Classes.

public sealed class Shape permits Circle, Rectangle, Square {

// Common fields and methods of Shape...

public final class Circle extends Shape {
public void draw() { /* draw a Circle */ }
}

public sealed class Rectangle extends Shape permits TransparentRectangle, FilledRectangle {
/public void draw() { /* draw a Rectangle */ }
}

public non-sealed class Square extends Shape {
public void draw() { /* draw a Square */ }
}

public final class TransparentRectangle extends Rectangle {
// Specific to TransparentRectangle...
}

public final class FilledRectangle extends Rectangle {
// Specific to FilledRectangle...
}
public final class Square extends Rectangle {
public void draw() { /* draw a square */ }
// Square-specific methods...
}
}

Benefits of sealed classes:

  • Compiler Enforcement: The Java compiler enforces the rules of sealed classes. If a class is declared to extend a sealed class but is not listed in its permitted subclasses, the compiler will reject it.
  • Reflection API: Java’s reflection API has been updated to recognize sealed classes and their permitted subclasses.
  • Pattern Matching: Sealed classes enhance pattern matching by ensuring that all possible subtypes are covered in a switch expression, thus avoiding the need for a default case.

Lets Look at the example of Pattern Matching using instanceof

public void processShape(Shape shape) {
if (shape instanceof Circle circle) {
circle.draw();
} else if (shape instanceof Rectangle rectangle) {
rectangle.draw();
} else if (shape instanceof Square square) {
square.draw();
}
}

Pattern Matching With Switch:

And this is another cool feature of Java 17.

public void processShape(Shape shape) {
switch (shape) {
case Circle circle -> circle.draw();
case Rectangle rectangle -> rectangle.draw();
case Square square -> square.draw();
}
}

JEP 412, titled “Foreign Function & Memory API (Incubator)

It is part of Java’s effort to evolve the Java foreign function and memory API, which was first introduced in Java 14 as an incubator module under JEP 370. The main goal of this API is to provide a pure Java API for calling native code and working with native memory, as a more efficient way of working with native functions as opposed to JNI.

import jdk.incubator.foreign.*;

public class NativeDemo {
public static void main(String[] args) throws Throwable {
// Load a native library, e.g., "libnative.so"
System.loadLibrary("native");

// Define a symbol lookup for the library
SymbolLookup lookup = SymbolLookup.loaderLookup();

// Define a method handle for a native function, e.g., "int nativeFunction(int)"
MethodHandle nativeFunction = CLinker.getInstance().downcallHandle(
lookup.lookup("nativeFunction").get(),
MethodType.methodType(int.class, int.class),
FunctionDescriptor.of(CLinker.C_INT, CLinker.C_INT)
);

// Call the native function
int result = (int) nativeFunction.invokeExact(42);
System.out.println("Result from native function: " + result);
}
}

Record Classes

A record class is a special kind of class in Java that is declared with the record keyword. It is a final class by default and implicitly finalizes its components, making it a perfect candidate for representing simple data carriers or data transfer objects (DTOs).

Key Features of Record Classes

  • Record Classes are Immutable.
  • Record implements boiler plate code like equals , Hash Code etc.
  • Record comes with canonical constructor which initializes all components.

Defining record

public record BodyMassIndex(double height, double weight, int age) {
// The record implicitly declares final fields x and y,
// a canonical constructor, and public accessor methods for them.
}
public class Main {
public static void main(String[] args) {
BodyMassIndex bmi1= new BodyMassIndex(5.3, 141.45,43);
// Records provide an implementation of equals(), hashCode() and toString()
BodyMassIndex bmi2 = new BodyMassIndex(5.3, 141.45,43);
System.out.println("BMIs are equal: " + bm1.equals(bm11));
System.out.println("BMI details: " + bmi);
}
}

I have tried to describe the most important features of Java 17 that I have used in my code most recently , please let me know what else do you want to know and I can cover that in my future articles. Thanks for reading and sharing and if you really like my content please clap.

--

--

Vikas Taank

I am new to Medium, trying to articulate my learnings so far . Please Join medium to read my articles. Please support- https://ko-fi.com/vikastaank