← Writing

JDK 21 Features: Final APIs, Preview Features, and a Runnable Example

JDK 21 makes virtual threads, sequenced collections, record patterns, and pattern matching for switch available without preview flags. String templates were still a preview feature in that release. A JDK upgrade does not give every new feature the same stability status.

Java 21 became generally available on September 19, 2023. This article revisits that release through a reproducible example. It does not recommend the latest JDK or a production patch version.

Feature status in JDK 21

Feature Status in JDK 21 What to check
Virtual threads Final Consider them for many I/O-bound tasks; they do not guarantee faster CPU computation
Sequenced collections Final Consistent APIs for first/last elements and reverse-ordered views
Record patterns and pattern matching for switch Final Deconstruct values and branch on patterns
String templates Preview Do not assume later JDK releases retain them
Structured concurrency Preview Assess separately from the finalization of virtual threads
Vector API Sixth Incubator Distinguish incubating APIs from final and preview features

This is a selected list. The JDK 21 release notes also document preview and incubator status. Check the Java 21 language changes for language feature status. String templates were not included in JDK 23; see their history and standard alternatives.

Compile without preview flags

The following code ran locally on Zulu JDK 21.0.1. That old patch version records the reproduction environment; it is not a production recommendation. First check that javac and java resolve to the same JDK 21 installation.

Jdk21Example.java

import java.util.ArrayList;
import java.util.List;

public class Jdk21Example {
    record Point(int x, int y) {}

    static String describe(Object value) {
        return switch (value) {
            case null -> "missing";
            case Point(int x, int y) -> "point=" + x + "," + y;
            default -> "other";
        };
    }

    public static void main(String[] args) throws InterruptedException {
        var names = new ArrayList<>(List.of("alpha", "beta", "gamma"));
        var reverse = names.reversed();
        names.set(0, "ALPHA");
        System.out.println(names.getFirst() + "/" + names.getLast());
        System.out.println(reverse);
        System.out.println(describe(new Point(2, 3)));
        System.out.println(describe(null));
        Thread worker = Thread.ofVirtual().start(() ->
                System.out.println("virtual=" + Thread.currentThread().isVirtual()));
        worker.join();
    }
}
javac --release 21 Jdk21Example.java
java Jdk21Example
ALPHA/gamma
[gamma, beta, ALPHA]
point=2,3
missing
virtual=true

reversed() returns a reverse-ordered view rather than an independent copy. After the first element in the original list changes, the last element in the reversed output is also ALPHA. Calling getFirst() on an empty collection would throw an exception; this example uses a nonempty list. The SequencedCollection API defines the view contract.

Point(int x, int y) is a record pattern, and case null handles null input separately. The virtual thread prints the final line, and join() waits for its completion. This checks API behavior without measuring throughput or latency. The virtual thread guide explains their suitability for concurrency dominated by I/O waits.

Before changing an application runtime, check JDK 21 compatibility for its framework, build tooling, and instrumentation agents. JDK feature status and a distributor’s support period are separate questions. Temurin 21 release history and binary selection covers how to check what a distributor actually published.

Discussion