Every new feature in Java 24

Today marks the release of the stable version of Java 24. This is a non-LTS (Long-Term Support) release that will be supported for the next six months. The announcement of Java 25 is scheduled for September 2025, and it will be an LTS release. Meanwhile, let’s take a fresh look at all the JEPs (JDK Enhancement Proposals) for JDK 24. There are as many as 24, which fits nicely with the new version number.
Stream Gatherers
JEP 485 introduces the Stream::gather(Gatherer)
operation, which allows defining custom intermediate operations on streams, such as filtering, windowing, and transforming. This aims to replace forcing using collect()
with a new purpose-built syntax with a new one. Essentially, gatherers maintain state and can operate in parallel. Java offers several built-in implementations (fold
, mapConcurrent
, scan
, windowFixed
, windowSliding
), but custom ones can also be written. The simplified syntax looks like this:
source.gather(a).gather(b).gather(c).collect(...)
As you can see, gather
is an intermediate step, while collect
should be the final step.
This is the only stable change in commonly used APIs in this release.
Improvements - Mainly for Cloud
Java strives to be faster and consume less memory, primarily because the Java team wants it to dominate cloud environments as well.
Compact Object Headers
Java 24 experiments with reducing object headers (JEP 450). It reduces the object header size in the HotSpot JVM from 96–128 bits to 64 bits on 64-bit architectures (x64, AArch64). While the reduction may seem minimal, the Java team noticed that most Java objects are small, causing the headers to take up as much as 20% of the total size.
This change is still experimental but could have a significant impact on application performance in the future.
Ahead-of-Time Class Loading & Linking
JEP 483 introduces an AOT (Ahead-Of-Time) mechanism, which speeds up application startup time in the JVM by loading and linking classes earlier. The Java team noticed that most applications tend to start the same way, and they decided to take advantage of this. After a "training" run of the application, an AOT cache file is created, which speeds up subsequent application starts.
Linking Run-Time Images without JMODs
JEP 493 allows the creation of custom runtime images using the jlink tool, without needing JMOD files. This reduces the installed JDK size by about 25%. This feature must be enabled during JDK compilation but is not active by default.
Synchronize Virtual Threads without Pinning
JEP 491 changes the behavior of virtual threads. Previously, when synchronization (synchronized) was used in the code, the thread had to be pinned to a system thread. This was problematic because there are fewer system threads than possible virtual threads. Now, virtual threads will dynamically mount and unmount from system threads in such situations, similar to how I/O blocking operations work.
Useful New Features That Are... Almost Ready
In the new version, many JEPs are in preview, incubator, or experimental phases. When a feature is in preview, it may still change slightly, but the overall concept remains the same. The incubator gradually develops features and is used for larger changes that require multi-stage feedback. Experimental features might never make it to a stable version of Java if they do not meet expectations.
Key Derivation Function API (Preview)
JEP 478 introduces the Key Derivation Function (KDF) API in Java 24, which allows creating additional keys based on a secret key and other data.
Class-file API
JEP 484 introduces a standard API for parsing, generating, and transforming class files in Java. The goal is to simplify the processing of class files according to the JVM format definition, eliminating dependencies on external libraries like ASM.
Scoped Values
JEP 487 introduces scoped values, which allow sharing immutable data between methods within the same thread and with child threads. Scoped values are easier to understand than thread-local variables, offering better performance and lower memory costs, especially when used with virtual threads and structural concurrency.
This API has been gradually developed through JEP 429 (JDK 20), JEP 446 (JDK 21), JEP 464 (JDK 22), and JEP 481 (JDK 23). In JDK 24, several improvements were made, including the removal of the callWhere and runWhere methods, which simplified the API. The feature is still in preview, but it may debut as stable in Java 25.
Primitive Types in Patterns, instanceof, and switch (Second Preview)
This feature extends pattern matching capabilities in Java, allowing the use of primitive types in instanceof and switch constructs. This aims to solve issues with safe type casting. Pattern matching has been continuously evolving, with each release in recent years bringing improvements to this mechanism.
Vector API
The new Vector API is in its ninth incubator phase (JEP 489). As we discussed earlier, the Java team is primarily waiting for Project Valhalla, but this time there are some new features, though they are not significant enough to delve into further.
Flexible Constructor Bodies
JEP 492 introduces the ability to perform instructions before calling another constructor (super(..) or this(..)), allowing instance fields to be initialized before the parent constructor is called. This makes object construction more flexible and reliable, especially when overriding methods. The change splits the constructor body into a prologue and epilogue, simplifying object initialization. This is a preview feature.
Module Import Declarations
JEP 494 introduces the ability to import all packages exported by a module with a single import module declaration, simplifying the use of modular libraries. This feature is in the preview phase, allowing easier use of APIs from multiple packages without the need for manual imports.
Simple Source Files and Instance Main Methods
The 4th preview of this feature aims to make it easier to write a “Hello World” program in Java (JEP 495). Seriously, this change is designed to allow you to write something like this:
void main() {
println("Hello, World!");
}
Structured Concurrency
JEP 499 is the 4th preview for the Structured Concurrency feature. Again, no major changes yet, as it’s awaiting more feedback from the community. This feature enables breaking a large task into many smaller steps, each performed in separate threads. The whole task is treated as a single unit of work, hence the name.
Quantum-Resistant Cryptography
JEP 496 introduces a quantum-resistant key encapsulation mechanism (ML-KEM) into Java, designed to protect against attacks from quantum computers. Very similarly named, JEP 497 introduces a quantum-resistant digital signature algorithm (ML-DSA).
Garbage Collectors
What would a new Java 2X release be without changes to the garbage collectors? A rhetorical question, but it’s obvious—it’s an essential part of the update. This time, there are 3 changes.
Generational Shenandoah
Java 24 introduces an experimental generational mode for the Shenandoah garbage collector (JEP 404). It divides memory into younger and older generations, which allows for more efficient memory management and shorter GC pauses. The mode can be enabled using the flag -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational
. This change is experimental but could bring benefits in cloud environments.
ZGC: Removal the Non-Generational Mode
JEP 490 removes the non-generational mode from ZGC, leaving only the generational mode. The goal is to reduce the maintenance cost of two modes. After these changes, options related to ZGenerational will no longer work, and ZGC will default to the generational mode.
Late Barrier Expansion for G1
JEP 475 optimizes the handling of G1 barriers in the C2 compiler by delaying their expansion until a later stage in the compilation process. This change reduces compiler overhead by 10-20%, simplifies the code, and eliminates errors due to improper operation order. Barriers will only be expanded when generating machine code, which reduces compiler load while maintaining the quality of the generated code.
Farewell to...
Prepare to Restrict the Use of JNI
Java 24 will introduce warnings for programs using JNI (Java Native Interface) (JEP 472). This is a sign of future changes—access to JNI will be limited by default in upcoming Java versions.
This is not a surprise, as two versions ago, Java introduced the Foreign Function & Memory API. Java developers suggested that this would be a safer and more modern successor to JNI. For now, JNI still works, but it's worth considering migration.
Remove the Windows 32-bit x86 Port
JEP 479 removes support for the Windows 32-bit x86 port, which was deprecated in JDK 21. Meanwhile, JEP 501 marks the 32-bit Linux port as “to be removed.”
Warn upon Use of Memory-Access Methods in sun.misc.Unsafe
JEP 498 introduces a warning that will appear when calling memory access methods from the sun.misc.Unsafe class, which were deprecated in JDK 23. These methods have been replaced by safer APIs like VarHandle (JEP 193) and the Foreign Function & Memory API (JEP 454). The goal is to facilitate the migration of applications to more modern, supported solutions.
Permanently Disable the Security Manager
JEP 486 continues the removal of the Security Manager, which has been used for securing code in Java. Due to its limited significance, especially in server-side applications, and the maintenance costs, it was deprecated in Java 17 (JEP 411).
Summary
This is quite a big release, with as many as 24 different enhancements. However, there were only a few stable features. Of course, there are some improvements dedicated to cloud environments, garbage collectors, and stream gatherers, but the rest are basically announcements for future changes.
Many of these will likely become stable in Java 25, the next LTS release, which will arrive in September. However, there are so many changes that we have some doubts whether they will manage to finalize everything in time.
What do you think? Share your thoughts in the comments. Meanwhile, let’s start the countdown to September and the release of Java 25 LTS.