New Features in Java 21: Project Amber, Loom, Panama, and Core Library Enhancements
Java 21, released on September 19 as a long‑term‑support release with eight years of Oracle support, introduces fifteen JEPs—including preview string templates, record patterns, switch pattern matching, virtual threads, scoped values, structured concurrency, foreign function & memory APIs, and a new sequenced‑collection interface—along with numerous performance, security, and deprecation updates, all illustrated with code examples.
On September 19, Oracle announced the official release of Java 21, the 12th version since the six‑month release cadence began, and the next long‑term‑support (LTS) release with a guaranteed eight‑year support window; Oracle also extended Java 11 support to at least January 2032.
The release fixes 24,196 JIRA issues, contributed by Oracle staff and the broader community, with notable contributions from Chinese companies such as Tencent, Alibaba, Huawei, and Loongson.
Overview of Java 21 New Features
Java 21 bundles fifteen JEPs, including six preview features and one incubating feature, grouped into six major areas.
Project Amber
JEP 430 – String Templates (preview)
Provides a concise syntax for runtime‑evaluated strings that mix literal text and expressions, improving readability and safety.
String name = "Joan";
String info = STR."My name is \{name}"; // template expression
assert info.equals("My name is Joan");Compilation and execution require the --enable-preview flag, e.g.:
javac --release 21 --enable-preview Test.java
java --enable-preview TestJEP 440 – Record Patterns
Extends pattern matching to deconstruct record instances directly.
record Point(int x, int y) {}
static void printSum(Object obj) {
if (obj instanceof Point p) {
System.out.println(p.x() + p.y());
}
}
// New form in Java 21
static void printSum(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println(x + y);
}
}JEP 441 – Switch Pattern Matching
Enables pattern‑based cases in switch expressions and statements.
static String formatter(Object obj) {
String formatted = "unknown";
if (obj instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (obj instanceof Long l) {
formatted = String.format("long %d", l);
} else if (obj instanceof Double d) {
formatted = String.format("double %f", d);
} else if (obj instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
// New switch‑pattern version
static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
}JEP 443 – Unnamed Patterns and Variables (preview)
Introduces the underscore syntax for ignored components and variables.
int acc = 0;
for (Order _ : orders) {
if (acc < LIMIT) { /* ... */ acc++; }
}
String s = ...
try {
int i = Integer.parseInt(s);
// use i
} catch (NumberFormatException _) {
System.out.println("Bad number: " + s);
}JEP 445 – Unnamed Classes and Instance Main Methods (preview)
Simplifies the entry point, allowing a class without the usual public static void main signature.
class HelloWorld {
void main() {
System.out.println("Hello, World!");
}
}Project Loom
JEP 444 – Virtual Threads
Introduces lightweight virtual threads that run on a small number of platform threads, dramatically improving scalability for high‑throughput concurrent applications.
void handle(Request request, Response response) {
var url1 = ...;
var url2 = ...;
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
var f1 = executor.submit(() -> fetchURL(url1));
var f2 = executor.submit(() -> fetchURL(url2));
response.send(f1.get() + f2.get());
} catch (ExecutionException | InterruptedException e) {
response.fail(e);
}
}
String fetchURL(URL url) throws IOException {
try (var in = url.openStream()) {
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
}JEP 446 – Scoped Values (preview)
Provides a safe, efficient way to share immutable data across many virtual threads without using thread‑local variables.
final static ScopedValue
V = ScopedValue.newInstance();
// In some method
ScopedValue.where(V, value).run(() -> { /* V.get() can be used here */ });
// Later in a called method
Object val = V.get();JEP 453 – Structured Concurrency (preview)
Offers a unified API ( java.util.concurrent.StructuredTaskScope ) to manage a group of related tasks as a single unit, simplifying error handling and cancellation.
Project Panama
JEP 442 – Foreign Function & Memory API (3rd preview)
Enables Java code to call native libraries and access off‑heap memory safely via the java.lang.foreign package.
JEP 448 – Vector API (6th incubating)
Introduces VectorSpecies<E> to express vector computations that the JVM can compile to optimal SIMD instructions on supported CPUs.
Core Library Enhancements
JEP 431 – Sequenced Collections
Adds the SequencedCollection<E> interface, giving collections a well‑defined iteration order and convenient access to first/last elements.
JEP 439 – Generational ZGC
Extends the Z Garbage Collector to manage young and old generations separately, improving pause times for many workloads.
JEP 452 – Key‑Encapsulation Mechanism (KEM) API
Introduces a new class for public‑key‑based encryption of symmetric keys.
JEP 449 – Deprecate 32‑bit x86 Builds
Marks Windows 32‑bit builds as deprecated with plans for removal.
JEP 451 – Prepare to Disallow Dynamic Proxy Loading
Emits warnings when agents are dynamically loaded into a running JVM, preparing for future default prohibition.
Java 21 is now available for download at the official Oracle JDK page.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.