What’s New in Java 24? 24 Game‑Changing Features Explained
Java 24, the latest non‑LTS release, brings 24 new features across security, performance, and language enhancements—including KDF APIs, ahead‑of‑time class loading, a new class‑file API, stream gatherers, scoped values, and quantum‑resistant signatures—while previewing Java 25 for September.
JEP 478: Key Derivation Function API (Preview)
The Key Derivation Function API provides a way to derive additional keys from an initial secret and other data, supporting algorithms such as HKDF and the future Argon2, which is important for modern cryptography and quantum‑resistant environments.
<code>// Create a KDF object using HKDF‑SHA256 algorithm
KDF hkdf = KDF.getInstance("HKDF‑SHA256");
// Create Extract and Expand parameter specifications
AlgorithmParameterSpec params =
HKDFParameterSpec.ofExtract()
.addIKM(initialKeyMaterial) // set initial key material
.addSalt(salt) // set salt value
.thenExpand(info, 32); // set expand info and target length
// Derive a 32‑byte AES key
SecretKey key = hkdf.deriveKey("AES", params);
// The same KDF object can be reused for other derivations
</code>JEP 483: Ahead‑of‑Time Class Loading and Linking
Traditional JVMs load and link classes dynamically on each start, which hurts startup time for microservices or serverless functions. This feature caches loaded and linked classes, reducing startup latency by over 40% for large Spring‑based applications, without requiring code changes—only the JVM flag
-XX:+ClassDataSharingis needed.
JEP 484: Class‑File API
The Class‑File API, previewed in JDK 22 (JEP 457) and JDK 23 (JEP 466) and finalized in JDK 24, offers a standardized way to parse, generate, and transform Java class files, replacing third‑party libraries such as ASM.
<code>// Create a ClassFile object, the entry point for class‑file manipulation.
ClassFile cf = ClassFile.of();
// Parse a byte array into a ClassModel.
ClassModel classModel = cf.parse(bytes);
// Build a new class file, removing all methods whose names start with "debug".
byte[] newBytes = cf.build(classModel.thisClass().asSymbol(),
classBuilder -> {
// Iterate over all class elements.
for (ClassElement ce : classModel) {
// Keep the element unless it is a method named with "debug" prefix.
if (!(ce instanceof MethodModel mm && mm.methodName().stringValue().startsWith("debug"))) {
classBuilder.with(ce);
}
}
});
</code>JEP 485: Stream Gatherers
The new
Stream::gather(Gatherer)operation lets developers define custom intermediate operations for more complex data transformations, such as sliding windows, custom deduplication, or stateful aggregations, extending the capabilities of the existing Stream API.
Example of using
Stream::gatherto deduplicate strings by length:
<code>var result = Stream.of("foo", "bar", "baz", "quux")
.gather(Gatherer.ofSequential(
HashSet::new, // initial state: a HashSet to store encountered lengths
(set, str, downstream) -> {
if (set.add(str.length())) {
return downstream.push(str);
}
return true; // continue processing the stream
}
))
.toList(); // result == [foo, quux]
</code>JEP 486: Permanent Removal of the Security Manager
JDK 24 disables the Security Manager entirely; even the
-Djava.security.managerflag no longer works. The feature is removed because it is complex, rarely used, and costly to maintain.
JEP 487: Scoped Values (Fourth Preview)
Scoped Values provide an immutable data‑sharing mechanism that is superior to thread‑local variables, especially when using many virtual threads.
<code>final static ScopedValue<...> V = new ScopedValue<>();
// In some method
ScopedValue.where(V, <value>)
.run(() -> { /* ... V.get() ... */ });
// Anywhere within the lambda, V.get() returns the scoped value.
</code>JEP 491: Linking Runtime Images without JMOD Files
JDK now includes runtime images (the modules needed at runtime) and JMOD files. This feature allows the
jlinktool to create custom runtime images without requiring the JDK’s JMOD files, reducing the installation size by about 25%.
jlink is a command‑line tool introduced in Java 9 for building lightweight, modular JREs.
JMOD files describe Java modules, containing metadata and resources.
JEP 495: Simplified Source Files and Instance Main Methods (Fourth Preview)
This feature simplifies the declaration of the
mainmethod, making it easier for beginners to start with Java.
<code>public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
</code> <code>class HelloWorld {
void main() {
System.out.println("Hello, World!");
}
}
</code> <code>void main() {
System.out.println("Hello, World!");
}
</code>JEP 497: Quantum‑Resistant Digital Signature Algorithm (ML‑DSA)
JDK 24 adds support for the module‑lattice‑based digital signature algorithm (ML‑DSA), a quantum‑resistant algorithm standardized in NIST’s FIPS 204, preparing Java for future quantum‑computing threats.
JEP 498: Warnings for Unsafe Memory‑Access Methods
JDK 23 (JEP 471) deprecated
sun.misc.Unsafememory‑access methods, which will be removed in future releases. JDK 24 now emits a runtime warning the first time any such method is invoked. Safer alternatives are:
java.lang.invoke.VarHandle: introduced in JDK 9 (JEP 193) for safe heap memory operations.
java.lang.foreign.MemorySegment: introduced in JDK 22 (JEP 454) for safe off‑heap memory access, often used together with
VarHandle.
<code>import jdk.incubator.foreign.*;
import java.lang.invoke.VarHandle;
// Class demonstrating off‑heap integer buffer management.
class OffHeapIntBuffer {
private static final VarHandle ELEM_VH = ValueLayout.JAVA_INT.arrayElementVarHandle();
private final Arena arena;
private final MemorySegment buffer;
public OffHeapIntBuffer(long size) {
this.arena = Arena.ofShared();
this.buffer = arena.allocate(ValueLayout.JAVA_INT, size);
}
public void deallocate() { arena.close(); }
public void setVolatile(long index, int value) {
ELEM_VH.setVolatile(buffer, 0L, index, value);
}
public void initialize(long start, long n) {
buffer.asSlice(ValueLayout.JAVA_INT.byteSize() * start,
ValueLayout.JAVA_INT.byteSize() * n)
.fill((byte) 0);
}
public int[] copyToNewArray(long start, int n) {
return buffer.asSlice(ValueLayout.JAVA_INT.byteSize() * start,
ValueLayout.JAVA_INT.byteSize() * n)
.toArray(ValueLayout.JAVA_INT);
}
}
</code>JEP 499: Structured Concurrency (Fourth Preview)
Structured Concurrency, introduced in JDK 19, treats multiple tasks running in different threads as a single unit of work, simplifying error handling, improving reliability, and enhancing observability. It works especially well with virtual threads.
<code>try (var scope = new StructuredTaskScope<Object>()) {
Future<Integer> f1 = scope.fork(task1);
Future<String> f2 = scope.fork(task2);
scope.join(); // wait for all subtasks
// process results or re‑throw exceptions
} // scope is automatically closed
</code>The next long‑term‑support release, Java 25, is scheduled for September.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.