Java 21, released in September 2023, is a Long-Term Support (LTS) release that finalizes several preview features from Java 17–20 and introduces powerful new capabilities. This document explains each major feature in Java 21 by detailing:
- What the feature is
- Why it was added
- How it changes previous behavior
- Examples to illustrate the change
- Benefits and impact
1. String Templates (JEP 430 – Preview)
What: Introduces template expressions to simplify and secure string composition.
Why: Reduces errors from concatenation and formatting, improves code readability, and supports customizable templates.
Before:
String name = "Alice"; String greeting = "Hello, " + name + "!";
Now:
String name = "Alice";
String greeting = STR."Hello, \{name}!";
Benefit: Cleaner syntax, fewer runtime formatting issues, extensible templates.
2. Record Patterns (JEP 440 – Final)
What: Enables pattern matching on records.
Why: Improves destructuring of data structures in conditionals and switch statements.
Before:
record Person(String name, int age) {}
if (obj instanceof Person) {
Person p = (Person) obj;
System.out.println(p.name());
}
Now:
if (obj instanceof Person(String name, int age)) {
System.out.println(name);
}
Benefit: Reduces boilerplate, increases clarity.
3. Pattern Matching for switch (JEP 441 – Final)
What: Adds pattern matching to switch expressions.
Why: Enhances type-safety and expressiveness for control flow.
Before:
switch (obj.getClass().getSimpleName()) {
case "String": ...
case "Integer": ...
}
Now:
switch (obj) {
case String s -> System.out.println("String: " + s);
case Integer i -> System.out.println("Integer: " + i);
default -> System.out.println("Unknown");
}
Benefit: More concise, safe, and expressive branching.
4. Virtual Threads (JEP 444 – Final)
What: Introduces lightweight, JVM-managed threads.
Why: Simplifies writing scalable, high-throughput concurrent applications.
Before:
Thread t = new Thread(() -> handleRequest()); t.start();
Now:
Thread t = Thread.startVirtualThread(() -> handleRequest());
Benefit: Enables millions of concurrent threads with minimal resource overhead.
5. Structured Concurrency (JEP 453 – Preview)
What: Treats multiple related tasks as a single unit of work.
Why: Improves error handling and task lifecycle management in concurrent code.
Before: Manual coordination:
ExecutorService es = Executors.newFixedThreadPool(2); Future<String> user = es.submit(...); Future<Integer> score = es.submit(...);
Now:
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(...);
Future<Integer> score = scope.fork(...);
scope.join();
scope.throwIfFailed();
}
Benefit: Simpler and safer parallel task orchestration.
6. Scoped Values (JEP 446 – Preview)
What: Provides a safer and more efficient alternative to ThreadLocal for storing contextual information.
Why: Avoids common pitfalls of ThreadLocal in a multithreaded or virtual-thread environment.
Before:
ThreadLocal<String> user = new ThreadLocal<>();
user.set("admin");
Now:
ScopedValue.where(USER, "admin").run(() -> {
System.out.println(USER.get());
});
Benefit: Immutable, confined to execution scope, and supports virtual threads.
7. Foreign Function & Memory API (JEP 442 – Preview)
What: Enables Java programs to interact with native libraries and memory without JNI.
Why: JNI is error-prone and hard to use; this API offers a safer, more idiomatic alternative.
Before: JNI:
JNIEXPORT void JNICALL Java_MyClass_nativeMethod(JNIEnv*, jobject);
Now:
Linker linker = Linker.nativeLinker(); SymbolLookup lookup = SymbolLookup.loaderLookup();
Benefit: Safer, faster, and easier native access.
8. Vector API (JEP 448 – 6th Incubator)
What: Provides a set of APIs for SIMD (Single Instruction, Multiple Data) computations.
Why: Leverages CPU vector instructions for performance gains.
Before:
for (int i = 0; i < arr.length; i++) {
arr[i] += 1;
}
Now:
IntVector vector = IntVector.fromArray(IntVector.SPECIES_256, arr, 0); vector = vector.add(1); vector.intoArray(arr, 0);
Benefit: High-performance computing through vectorized operations.
9. Unnamed Classes and Instance Main Methods (JEP 445 – Preview)
What: Allows writing Java programs without class declaration for simpler entry points.
Why: Makes Java more approachable for new learners and quick scripts.
Before:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
Now:
void main() {
System.out.println("Hello World");
}
Benefit: Reduces boilerplate in small programs.
10. Unnamed Patterns and Variables (JEP 443 – Preview)
What: Introduces _ as a placeholder for unused variables and patterns.
Why: Cleaner code when parts of a pattern are irrelevant.
Before:
if (obj instanceof Point p) {
int x = p.x();
}
Now:
if (obj instanceof Point(_, int y)) {
System.out.println(y);
}
Benefit: Reduces noise and clarifies intent.
11. Generational ZGC (JEP 439 – Final)
What: Enhances the Z Garbage Collector with generational heap layout.
Why: Improves performance by separating short-lived (young) and long-lived (old) objects.
Before:
ZGC managed a single heap generation.
Now:
Young and old generations are managed separately.
Benefit: Better throughput, reduced pause times.
12. Deprecate Windows 32-bit x86 Port (JEP 449 – Final)
What: Deprecates the 32-bit Windows x86 port.
Why: Outdated platform with minimal usage. Reduces maintenance burden.
Impact: Warns on 32-bit JVM use; may be removed in a future release.
13. Prepare for Finalization Removal (JEP 451 – Final)
What: Provides warnings and infrastructure for the future removal of object finalization.
Why: Finalization is unreliable and causes performance/memory issues.
Impact: Finalizers still work, but tooling emits warnings. Use Cleaner or try-with-resources.
14. Key Encapsulation Mechanism (JEP 452 – Final)
What: Introduces a standard API for KEM (Key Encapsulation Mechanism).
Why: Supports modern cryptographic protocols like HPKE for secure key exchange.
Use Case: Hybrid encryption with key derivation.
Benefit: Enhances cryptographic capabilities for secure communications.
Summary
Java 21 is a feature-rich LTS release focused on:
- Modern language enhancements (string templates, pattern matching, unnamed variables)
- Scalable concurrency (virtual threads, structured concurrency, scoped values)
- Better performance (Generational ZGC, Vector API)
- Improved native integration (FFM API)
- Security and maintainability (KEM, finalization deprecation)
Adopting Java 21 ensures access to modern language features while staying on a stable, supported platform.