Java 24 was released on 18.03.2025. Fittingly, the release also contains exactly 24 JEPs. Here is an overview of the new features.
The preview features
A new preview is included:
- JEP-478 - Key Derivation Function API (Preview)
Key Derivation Functions (KDFs) use cryptographic inputs such as base keys, salt and pseudo-random functions to generate new, strong keys. They allow the reproducible and secure generation of different keys, similar to password hashing. KDFs extract or extend key material by combining a keyed hash with additional entropy. Given the increasing threat of quantum computing, post-quantum secure cryptography is becoming more important. The Java platform aims to facilitate the transition to quantum-safe algorithms with Hybrid Public Key Encryption (HPKE) and a new KDF API. This promotes interoperability, supports standards such as PKCS#11 and enables more modern password hashing methods (e.g. Argon2). This will significantly increase the security and flexibility of future applications.
Code example from the JEP:
// Create a KDF object for the specified algorithm
KDF hkdf = KDF.getInstance("HKDF-SHA256");
// Create an ExtractExpand parameter specification
AlgorithmParameterSpec params =
HKDFParameterSpec.ofExtract()
.addIKM(initialKeyMaterial)
.addSalt(salt).thenExpand(info, 32);
// Derive a 32-byte AES key
SecretKey key = hkdf.deriveKey("AES", params);
// Additional deriveKey calls can be made with the same KDF object
-> to the JEP-478
It also includes a number of preview features that were already included in the previous versions, and which I already wrote about in previous blog posts had reported:
- JEP-487 - Scoped Values (Fourth Preview): A lightweight alternative to
ThreadLocal. The methodscallWhereandrunWherehave been removed to enable a completely fluid API. - JEP-488 - Primitive Types in Patterns, instanceof and switch (Second Preview)No changes compared to the First Preview.
- JEP-489 - Vector API (Ninth Incubator): an API for calculating with vectors, with a number of customizations. The API will remain in incubator status until the features of Project Valhalla (addition of value objects to Java) will be available as preview features.
- JEP-492 - Flexible Constructor Bodies (Third Preview): This feature makes it possible to call statements in constructors under certain conditions before calling
super()orthis()to set. No significant changes since the Second Preview. - JEP-494 - Module Import Declarations (Second Preview): allows the import of all packages of a Java module with import
module <module-name>. - JEP-495 - Simple Source Files and Instance Main Methods (Fourth Preview)The new version : is intended to make it easier for beginners to get started with Java by simplifying the writing of small programs. Apart from adjustments to the terminology and the title, there are no changes compared to the Third Preview.
- JEP-499 - Structured Concurrency (Fourth Preview): an API for more readable, maintainable and reliable concurrent code. No changes to the previous third preview.
Experimental features
In addition to the previews, there are also two experimental features:
JEP-404 - Generational Shenandoah (Experimental)
The Shenandoah Garbage Collector is extended by an experimental generational mode, which is intended to improve memory consumption, CPU/energy efficiency and resilience to load peaks - without replacing the proven non-generational variant. In this approach, the Java heap is divided into two generations: a young generation, in which most short-lived objects are collected, and an old generation, which manages long-term objects. The aim is to reduce memory requirements while maintaining low GC pauses (-> to the JEP-404).
JEP-450 - Compact Object Headers (Experimental)
Object headers, which currently require between 96 and 128 bits in the HotSpot JVM, are to be compressed so that their size is only 64 bits. It is expected that this will reduce the memory consumption of Java applications by 10-20% (-> to the JEP-450).
The new features
These are the official new features included in JDK 24.
JEP-472 - Prepare to Restrict the Use of JNI
The JVM now issues warnings when an application accesses native code via the Java Native Interface (JNI). This is already the case with the Foreign Function & Memory API (FFM), which also allows the execution of native code. The longer-term goal is to only allow access to native code in later JDK versions if this is explicitly activated using a command line parameter, as interaction with native code is risky and is not even required in the majority of Java applications (-> to the JEP-472).
JEP-475 - Late Barrier Expansion for G1
The barrier implementation of the G1 garbage collector, which records information about memory accesses by the application, is simplified. The corresponding G1 functionalities are decoupled from the internals of the C2 just-in-time compiler. This enables GC developers to further optimize and reduce the overhead of G1 without having to have a deep understanding of the C2 compiler (-> to the JEP-475).
JEP-479 - Remove the Windows 32-bit x86 Port
In October 2025, support for Windows 10, the last version of Windows that is still available as a 32-bit version, will be discontinued. In addition, the implementation of virtual threads for 32-bit will fall back to kernel threads, which means that the added value of Project Loom is virtually non-existent. Support for the 32-bit port of the JDK for Windows will therefore be discontinued for version 24 (-> to the JEP-479).
JEP-501 - Deprecate the 32-bit x86 Port for Removal
The costs of maintaining the 32-bit port for Linux far outweigh the benefits. Marking it as deprecated and removing it in a later release will free up developer resources to accelerate the development of new features and improvements. The removal of the 32-bit port is planned for JDK 25.
JEP-483 - Ahead-of-Time Class Loading & Linking
This function is based on the Class Data Sharing (CDS) of the HotSpot JVM and aims to further accelerate the launch of Java applications.
When starting a Java program, the classes used must first be read from disk, parsed and linked. This happens again each time the program is started and always takes a certain amount of time. As of Java 24, the JVM now offers the option of creating an ahead-of-time cache in which the loaded and linked classes of the application are stored and which can then be used when the application is started.
The cache is created in 2 steps (this process will be optimized in the future). First a AOTConfiguration in which the classes used by the application are listed. To do this, start the application with two special command line parameters:
$ java -XX:AOTMode=record -XX:AOTConfiguration=myapp.aotconf -cp myapp.jar \ de.doubleSlash.MyApp
Based on the AOTConfiguration in the file myapp.aotconf the cache is now created:
$ java -XX:AOTMode=create -XX:AOTConfiguration=myapp.aotconf \
-XX:AOTCache=myapp.aot -cp myapp.jar
The application is not executed in this step. Only the cache is created and stored in the file myapp.aot filed.
This can now be used as follows when starting the application:
$ java -XX:AOTCache=myapp.aot -cp myapp.jar de.doubleSlash.MyApp
When creating the AOTConfiguration you should ensure that all classes required by the application end up in the configuration file in order to achieve the best possible efficiency gain. This is not always the case, especially with dynamically loaded classes (e.g. via reflection). In contrast to ahead-of-time compilation (e.g. via GraalVM), however, it is not fatal if classes are missing from the AOT cache; these are then simply loaded and linked in the usual way when the application is started. However, the advantage of the cache for these classes then does not apply.
Performance measurements showed that the start time was reduced by more or less half. For more details on this feature, I recommend the JEPas well as the worth reading Blog post by Gunnar Morling on this topic, which was able to speed up the start of a Kafka server with the AOT cache by a whopping 59% (-> to the JEP-483).
JEP-484 - Class-File API
In the Java ecosystem, class files are often parsed, generated and transformed, especially in tools and frameworks that dynamically manipulate bytecode. Libraries such as ASM, BCEL and Javassist are used for this purpose - the JDK also uses its own solution. Due to new language and JVM features, the format of the class files is subject to constant further development, which is why a standardized, future-proof API is necessary to ensure responsiveness and effective independence from ASM for Java. The class file API developed for this purpose has now been finally published after two previews (-> to the JEP-484)
JEP-485 - Stream Gatherers
Also after two previews, the Stream Gatherers were finalized and officially included in the JDK. This is an extension point for the Stream API in the form of an interface called Gathererand a gather(...)-method, which can be used to implement stream operations that are not available in the API itself.
Here is an example of a simple gatherer that multiplies each element in a stream:
public static <T> Gatherer<T, ?, T> multiplyBy(int times) {
return Gatherer.ofSequential((state, element, downstream) -> {
for (int i = 0; i < times; i++) {
downstream.push(element);
}
return true;
});
}
The use in the stream looks like this:
List<String> multiplied = Stream.of("a", "b", "c")
.gather(multiplyBy(3))
.toList();
The result is a list that contains each element from the original stream three times, i.e. (a, a, a, b, b, b, c, c, c).
A number of Gatherer implementations, such as windowFixed, windowSliding or foldare available via the class Gatherers available.
The application of windowSliding looks something like this:
Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowSliding(3))
.forEach(System.out::println);
The issue:
[1, 2, 3] [2, 3, 4] [3, 4, 5]
-> to the JEP-485
JEP-486 - Permamently Disable the Security Manager
The Security Manager has not been the primary means of securing client-side Java code for many years. It was rarely used to secure server-side code and is expensive to maintain. It has therefore been replaced with JEP-411 (2021) is declared as deprecated for removal in Java 17. In the next step, the Java platform specification will be revised so that developers can no longer activate it and other platform classes will no longer reference it. This change will not affect the vast majority of applications, libraries and tools. The Security Manager API will be removed in a future release (-> to the JEP-486).
JEP-490 - ZGC: Remove the Non-Generational Mode
The Generational Mode in the ZGC Garbage Collector was set to JEP-439 introduced (JDK 21) and has been used since JEP-474 (JDK 23) is used by default. In order to save the maintenance costs for two different modes, the non-generational mode is removed from the ZGC (-> to the JEP-490).
JEP-491 - Synchronize Virtual Threads without Pinning
With the keyword synchronized In Java, you can mark places in the code that may only be executed by one thread at a time in order to prevent so-called race conditions in concurrent processing.
So far, the functionality of synchronized is bound to platform threads, which means that a platform thread is bound as long as it is in a synchronized-block (thread pinning). However, if virtual threads are used, i.e. lightweight threads, many of which can run on a single platform thread, the so-called "carrier thread", this becomes a problem. Frequent pinning over long periods of time can impair scalability. It can lead to "starvation" of threads or even deadlock if no virtual threads can be executed because all platform threads available to the JDK scheduler are either occupied by virtual threads or blocked in the JVM.
With this JEP, the functionality of synchronized so that it works independently of the carrier threads and the above-mentioned problems no longer occur (-> to the JEP-491)
JEP-493: Linking Run-Time Images without JMODs
With jlink can be used to create individual runtime images that only contain the JDK modules that are absolutely required by an application in the form of JMOD files, which results in a reduced size of the installed JDK. A complete JDK mainly consists of a runtime image, which represents the executable Java system, and the JMOD files, in which the modules of the runtime image are packaged. Since all classes, native libraries, configuration files and other resources are contained in both the runtime image and the JMOD files, complete JDK versions are larger and therefore require more resources than actually necessary. This JEP includes an optimization of jlinkwhich extracts the resources directly from the runtime image and thus eliminates the JMOD files. This can reduce the size of an installed JDK by around 25% (-> to the JEP-493).
JEP-496: Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism
This extension improves the security of Java applications by providing an implementation of the quantum-resistant Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM). KEMs are used to secure symmetric keys over insecure communication channels using public-key cryptography. ML-KEM is designed to be secure against future attacks by quantum computers. It was developed by the United States National Institute of Standards and Technology (NIST) in FIPS 203 standardized (-> to the JEP-496).
JEP-497: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm
This increases the security of Java applications by providing an implementation of the quantum-resistant Module-Lattice-Based Digital Signature Algorithm (ML-DSA). Digital signatures are used to detect unauthorized changes to data and authenticate the identity of signers. ML-DSA is designed to be secure against future attacks by quantum computers. It was developed by the United States National Institute of Standards and Technology (NIST) in FIPS 204 standardized (-> to the JEP-497).
JEP-498: Warn upon Use of Memory-Access Methods in sun.misc.Unsafe
In JEP-471 (JDK 23), the memory access functions from the class sun.misc.Unsafe marked as deprecated and for removal in a later release. Corresponding functionalities are now provided by official standard JDK APIs. Therefore, warnings are now issued at runtime if an application uses the old memory access methods of sun.misc.Unsafe used. The aim is to make developers aware of this and encourage them to migrate to the new APIs so that sun.misc.Unsafe can be removed in a later release (-> to the JEP-498).



