Core Java

Java 25 Features Overview

Java 25 (JDK 25) is poised to become a major milestone in the evolution of the Java platform. Scheduled for General Availability (GA) by September 2025, this release is a Long-Term Support (LTS) version, which means that developers and organisations can rely on extended updates and stability for years to come. Packed with performance enhancements, improved observability, memory optimisations, and forward-looking language features, Java 25 reflects the ongoing transformation of the Java ecosystem to meet modern application needs.

In this article, we will explore some of the exciting features of Java 25.

1. Compact Object Headers (JEP 519)

Compact object headers were introduced as an alternative object-header layout in JDK 24. Java 25 refines this feature, making it more suitable for general use in production environments.

Traditionally, Java object headers consume 96 bits to store metadata like the identity hash code and class pointer. With compact headers, this is reduced to 64 bits on 64-bit platforms such as x64 and AArch64. This leads to lower memory usage, improved heap density, and overall better performance.

To enable this feature, use the JVM option:

XX:+UseCompactObjectHeaders

2. Stable Values (JEP 502, Preview)

Java 25 introduces Stable Values, a new way to define immutable values that can be initialised once, at any time, even across threads. Unlike final fields, which must be set during construction, stable values offer more flexibility by allowing deferred initialization while ensuring thread safety. This helps improve application startup by delaying the setup of important values until they are actually needed, without sacrificing immutability or performance optimizations.

3. Scoped Values (JEP 506)

Java 25 introduces Scoped Values as a safer and more efficient alternative to ThreadLocal for sharing immutable data across threads. They are explicitly bound to a defined dynamic scope, making them ideal for passing context like user information or request metadata without relying on global or mutable state.

Scoped values integrate seamlessly with virtual threads and structured concurrency, offering a lightweight solution that avoids the memory leaks and synchronization overhead commonly associated with ThreadLocal. This makes them a powerful tool for modern, concurrent Java applications.

import java.lang.ScopedValue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ScopedValueWithVirtualThread {
    static final ScopedValue<String> USER = ScopedValue.newInstance();

    public static void main(String[] args) {
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

        ScopedValue.where(USER, "Thomas", () -> {
            executor.submit(() -> {
                // Access the scoped value inside the virtual thread
                System.out.println("Running as user: " + USER.get());
            });
        });

        executor.close(); // Clean up
    }
}

This example demonstrates how to use a scoped value to safely pass immutable context ("Thomas") into a virtual thread. The ScopedValue.where(...) method restricts the visibility of the value to the defined scope, ensuring thread safety. The virtual thread itself is launched using Executors.newVirtualThreadPerTaskExecutor(), enabling lightweight concurrency while preserving isolation in context propagation.

4. JFR Enhancements: CPU-Time Profiling, Cooperative Sampling, and Method Timing (JEP 509, JEP 518, JEP 520)

Java 25 expands the capabilities of JDK Flight Recorder (JFR), the built-in tool for profiling and monitoring Java applications. These enhancements aim to make performance analysis more precise and efficient in real-world environments.

JFR CPU-Time Profiling (JEP 509 – Experimental)

This feature enables JFR to use the Linux kernel’s CPU timer to record how much CPU time is spent in different parts of the application. It helps developers optimise performance on Linux systems. Support for other platforms may follow.

JFR Cooperative Sampling (JEP 518)

Improves the reliability of JFR stack sampling by collecting data only at safe execution points. This approach reduces sampling bias and ensures more consistent performance insights during asynchronous profiling.

JFR Method Timing & Tracing (JEP 520)

Allows JFR to record method execution times and call traces without modifying application code. Developers can configure it via command-line options, files, or tools like jcmd, making it easier to pinpoint bottlenecks and debug issues in production environments.

5. Generational Shenandoah GC (JEP 521)

Java 25 promotes Generational Shenandoah from an experimental feature to a fully supported product feature. This version of the Shenandoah garbage collector, first previewed in JDK 24, separates memory into young and old generations, improving efficiency and throughput.

According to the official proposal, the collector in JDK 24 introduced capabilities aimed at improving sustainable throughput, memory utilization, and resilience to load spikes. It also noted successful reports of the GC handling demanding workloads. Java 25 builds on this with further stability and performance enhancements.

6. Key Derivation Function API (JEP 510)

Java 25 finalises the Key Derivation Function (KDF) API, which was first introduced as a preview in JDK 24. This API supports cryptographic algorithms for generating keys from existing secrets and additional input data.

The goal is to support widely used algorithms like HKDF and Argon2, while allowing providers to implement them in Java or native code. It also enables the integration of KDFs into modern cryptographic protocols such as Hybrid Public Key Encryption and secure key exchange in TLS 1.3.

7. Structured Concurrency (JEP 505, Fifth Preview)

Structured Concurrency reaches its fifth preview in Java 25, following earlier previews in JDK 21–24 and incubation in JDK 19 and 20. It treats groups of related tasks as a single unit of work, making cancellation, error handling, and observability more predictable and reliable in concurrent applications.

Java 25 introduces API changes: StructuredTaskScope is now created using static factory methods instead of public constructors. A new zero-argument factory method handles common use cases by waiting for all subtasks to succeed or any one to fail.

import java.util.concurrent.StructuredTaskScope;

public class StructuredConcurrencyExample {
    public static void main(String[] args) throws InterruptedException {
        try (var scope = StructuredTaskScope.<String>open()) {
            var future1 = scope.fork(() -> fetchData());
            var future2 = scope.fork(() -> processData());

            scope.join();

            System.out.println(future1.get() + ", " + future2.get());
        }
    }

    static String fetchData() { return "Data"; }
    static String processData() { return "Processed"; }
}

8. Primitive Types in Patterns (JEP 507, Third Preview)

Java 25 includes a third preview of pattern matching enhancements that allow primitive types (like int, double, char, etc.) to be used in all pattern contexts—including instanceof and switch. This unifies pattern matching across all Java types, enabling safer, more expressive, and easier-to-read code without unsafe casting.

static void handle(Object obj) {
    if (obj instanceof int i) {
        System.out.println("int value: " + i);
    }

    switch (obj) {
        case double d -> System.out.println("double value: " + d);
        case char c   -> System.out.println("char value: " + c);
        default       -> System.out.println("Other type");
    }
}

9. Vector API (JEP 508, Incubator)

The Vector API continues as an incubator in Java 25, now in its 10th round since JDK 16. It enables high-performance computations by expressing operations that compile to optimised SIMD instructions on supported CPUs, delivering much better performance than traditional element-by-element operations.

Java 25 brings key improvements: native math libraries are now linked via the Foreign Function & Memory API, improving maintainability. It also adds auto-vectorization for Float16 operations on x64 CPUs, and allows VectorShuffle to read from and write to MemorySegment.

import jdk.incubator.vector.*;

public class VectorExample {
    static final FloatVector.Species SPECIES = FloatVector.SPECIES_256;

    public static void compute(float[] input, float[] output) {
        for (int i = 0; i < input.length; i += SPECIES.length()) {
            var vec = FloatVector.fromArray(SPECIES, input, i);
            var result = vec.mul(2.0f); // Vectorized multiplication
            result.intoArray(output, i);
        }
    }
}

This code demonstrates a vectorized loop that multiplies elements of a float array by 2 using hardware acceleration where supported.

10. PEM Encoding for Crypto Keys (JEP 470 – Preview)

Java 25 previews a new, easy-to-use API for working with PEM-encoded cryptographic objects, such as keys, certificates, and revocation lists. This feature simplifies converting between PEM text and standard binary formats like PKCS#8 (private keys), X.509 (certificates and public keys), and PKCS#8 v2.0 (encrypted or asymmetric keys).

Previously, the Java platform lacked a straightforward way to handle PEM encoding. This new API aims to fill that gap by making encoding and decoding both intuitive and standards-compliant for developers.

11. Ahead-of-Time (AOT) & Startup Improvements (JEP 514 & JEP 515)

Java 25 includes key enhancements to reduce startup time and improve overall runtime efficiency through better Ahead-of-Time (AOT) compilation support. These improvements focus on simplifying AOT usage and accelerating application warmup without changing existing code or workflows.

AOT Command‑Line Ergonomics (JEP 514)

This update streamlines the process of generating AOT caches by simplifying command-line usage for common scenarios. It builds on the AOT class loading and linking capabilities introduced in JDK 24, aiming to make AOT more accessible without introducing new workflows.

AOT Method Profiling (JEP 515)

Java 25 introduces method profiling support for AOT caches, allowing the JVM to use execution data from previous runs to optimize methods immediately at startup. This improves warmup performance without requiring code changes, using existing AOT infrastructure.

12. Deprecated or Removed Features

x86 32-bit Port Removed (JEP 503)

JDK 25 officially removes the x86 32-bit port—continuing Java’s trend of deprecating legacy architectures in favour of modern, high-performance systems.

13. Other Quality-of-Life Improvements

Java 25 brings a number of refinements to improve developer productivity and simplify common coding tasks. These updates aim to make Java more approachable for beginners while providing greater flexibility and expressiveness for experienced developers.

Flexible Constructor Bodies (JEP 513)

Finalized in Java 25 after multiple previews, flexible constructor bodies allow code to appear before super(...) or this(...) calls, as long as it doesn’t reference the object under construction. This makes constructors more natural to write and enables fields to be safely initialised before superclass code executes, enhancing both readability and safety.

class Item {

    private final int id;

    public Item(int id) {
        this.id = id;
        System.out.println("Item created with ID: " + id);
    }
}

class Product extends Item {

    private final String name;

    public Product(int inputId, String inputName) {
        // Safe pre-super() logic 
        int validatedId = (inputId > 0) ? inputId : 1;

        // Explicit super() 
        super(validatedId);

        this.name = (inputName != null) ? inputName : "Unnamed";
        System.out.println("Product name: " + name);
    }

    public static void main(String[] args) {
        new Product(-10, null);
    }
}

Module Import Declarations (JEP 511)

Java 25 enhances modular programming with module import declarations, letting developers import all exported packages of a module in one statement. This simplifies code that uses broad APIs and makes it easier for newcomers to work with modular libraries, without requiring the importing code itself to be modularised.

Instance Main Methods & Compact Source Files (JEP 512)

This feature, now finalised, allows simple class declarations and instance main methods, making it easier for newcomers to write their first Java programs. Developers can now create compact, single-class applications without boilerplate, while still having a smooth path to adopt advanced features as projects grow.

    void main() {
        IO.println("Hello from an instance main method!");
    }

14. Conclusion

In this article, we explored the new features in Java 25, a release that solidifies Java’s position as a robust, modern, and developer-friendly platform. From performance improvements like Shenandoah GC and compact headers to developer conveniences like structured concurrency and scoped values, JDK 25 is packed with upgrades that address both low-level runtime efficiency and high-level programming expressiveness.

This LTS release makes it ideal for enterprise adoption and long-term projects. Whether you are building microservices, high-performance systems, or secure enterprise apps, Java 25 provides a strong foundation for the future.

This article provided an overview of the new features introduced in Java 25.

Omozegie Aziegbe

Omos Aziegbe is a technical writer and web/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button