What's New in JDK 25: Key Features and Enhancements

    What's New in JDK 25: Key Features and Enhancements

    23/11/2025

    Java 25 is scheduled for release in September 2025. This release brings several significant features to the Java platform, including the finalization of Scoped Values, the introduction of Stable Values, and further refinements to Structured Concurrency. Let's explore the key features included in the Java 25 release.

    Feature Classifications in Java 25

    • Final Features: Fully implemented, tested, and officially part of the Java SE Platform.

    • Preview Features: Complete but not yet permanent features available for developer feedback, requiring the --enable-preview flag.

    • Incubator Features: Experimental APIs distributed in separate modules.

    • Experimental Features: Early, potentially unstable versions of VM-level features.

    1. Language Enhancements

    1.1 Stable Values (Preview)

    Stable Values are variables that can be set only once during an application's lifetime and stay unchanged after that. They provide a standardized way to lazily initialize constants, letting the JVM optimize them just like it does with final values.

    This feature solves the long-standing problem of safe lazy initialization in Java. It offers better performance than final fields (which must be initialized at creation) and better safety than double-checked locking or other lazy initialization patterns.

    You can learn more about Stable Values from this Stable Values Guide.

    Example:

    public class EmailService { private static final StableValue<SMTPClient> smtpClient = StableValue.of(); public static void sendEmail(String to, String subject, String body) { SMTPClient client = smtpClient.orElseSet(() -> new SMTPClient(loadConfiguration())); client.send(to, subject, body); } }

    1.2 Primitive Types in Pattern Matching (Third Preview)

    This feature extends pattern matching to work with primitive types in both instanceof and switch expressions. This enhancement simplifies code that needs to match primitive types, reducing boilerplate and improving readability.

    Example:

    public void processValue(Object obj) { switch (obj) { case int i -> System.out.println("Integer: " + i); case long l -> System.out.println("Long: " + l); case String s -> System.out.println("String: " + s); default -> System.out.println("Unknown: " + obj); } }

    Related: Pattern Matching in Java — Deep dive into pattern matching, sealed types, destructuring, and related features leading up to Java 25.

    1.3 Module Import Declarations (Final)

    Module Import Declarations allow developers to import all the packages exported by a module with a single declaration. This simplifies working with modular libraries by significantly reducing import statement verbosity.

    Example:

    import module java.base; void main() throws IOException { var names = List.of("Alice", "Bob", "Charlie"); Path filePath = Paths.get("test.txt"); Files.write(filePath, names); }

    1.4 Compact Source Files and Instance Main Methods (Final)

    This feature simplifies Java program structure for beginners by eliminating the need for explicit class declarations and static main methods in simple programs. It lowers the barrier to entry for learning Java by allowing students to write their first programs without needing to understand large amounts of boilerplate code.

    Example:

    void main() { System.out.println("Hello, World!"); }

    1.5 Flexible Constructor Bodies (Final)

    Flexible Constructor Bodies allow statements to appear before an explicit constructor invocation (super(...) or this(...)). This enables cleaner initialization logic and reduces the need for repetitive code in constructors, giving developers more freedom in how they structure their object initialization.

    Example:

    public UserProfile(String rawUsername, String rawEmail) { // Sanitize input before calling superclass constructor var sanitizedUsername = sanitize(rawUsername); var sanitizedEmail = sanitize(rawEmail); super(sanitizedUsername, sanitizedEmail); }

    2. Performance and Runtime Improvements

    2.1 Compact Object Headers (Final)

    This feature reduces the size of object headers in the HotSpot JVM from between 96 and 128 bits down to 64 bits on 64-bit architectures. By reducing the per-object overhead, this change reduces heap size, improves deployment density, and increases data locality.

    2.2 Generational Shenandoah

    Generational Shenandoah introduces a generational mode for the Shenandoah garbage collector. This improves performance for applications with high allocation rates by separating young and old objects, allowing for more frequent collection of short-lived objects without scanning the entire heap.

    3. Library Enhancements

    3.1 Scoped Values (Final)

    Scoped Values, now a finalized feature in Java 25, provide a safer and more structured way of sharing data within a thread and its child threads. They serve as a modern alternative to ThreadLocal.

    Scoped values address the limitations of ThreadLocal (unconstrained mutability, unbounded lifetime) by providing a immutable, bounded-lifetime data sharing mechanism. It is particularly important for Virtual Threads where ThreadLocal can be expensive.

    You can learn more about Scoped Values from this Scoped Values Guide.

    Example:

    public class UserContextDemo { public static final ScopedValue<String> userScopedVal = ScopedValue.newInstance(); public static void main(String[] args) { ScopedValue.where(userScopedVal, "Alice").run(() -> { processUserRequest(); }); } static void processUserRequest() { System.out.println("Processing for user: " + userScopedVal.get()); } }

    3.2 Structured Concurrency (Fifth Preview)

    Structured Concurrency is an API that treats groups of related tasks running in different threads as a single unit of work. This simplifies concurrent programming by eliminating common risks like thread leaks and cancellation delays, while improving reliability and observability of concurrent code.

    You can learn more about Structured Concurrency from this Structured Concurrency Guide.

    Example:

    public void generateReport(String stockSymbol) throws InterruptedException { try (var scope = StructuredTaskScope.open()) { var stockTask = scope.fork(() -> stockRepository.getStockHolding(stockSymbol)); var marketPriceTask = scope.fork(() -> stockAPIClient.getStockPrice(stockSymbol)); scope.join(); // Process results printReport(stockTask.get(), marketPriceTask.get()); } }

    3.3 Vector API (Tenth Incubator)

    The Vector API allows developers to express vector computations that reliably compile to optimal vector hardware instructions. This dramatically improves performance for computationally intensive applications by leveraging SIMD (Single Instruction, Multiple Data) hardware capabilities.

    3.4 Key Derivation Function API (Final)

    The Key Derivation Function API provides a standard API for Key Derivation Functions (KDFs). This addition provides standardized, secure methods for deriving cryptographic keys, making it easier to implement secure key management in Java applications.

    4. Security Enhancements

    4.1 PEM Encodings of Cryptographic Objects (Preview)

    This preview feature introduces a standard API for encoding and decoding cryptographic keys and certificates in the PEM format. This simplifies the handling of cryptographic artifacts, which are commonly exchanged in PEM format across different systems.

    5. Tooling and Observability Updates

    5.1 JFR CPU-Time Profiling (Experimental)

    This experimental feature enhances JDK Flight Recorder (JFR) to capture more accurate CPU-time profiling information on Linux. It provides deeper insights into application performance by accurately measuring CPU consumption of individual methods, helping developers identify optimization targets more effectively.

    5.2 JFR Method Timing & Tracing

    This update extends JFR with facilities for method timing and tracing via bytecode instrumentation. It allows recording complete and exact statistics for specific methods without source code modifications, moving beyond sample-based statistics for critical code paths.

    5.3 JFR Cooperative Sampling

    JFR Cooperative Sampling improves the stability of JFR when asynchronously sampling Java thread stacks by walking call stacks only at safepoints while minimizing safepoint bias. This enhances the reliability of profiling in production environments by preventing crashes that could occur with previous asynchronous sampling techniques.

    5.4 Ahead-of-Time Command-Line Ergonomics

    This feature simplifies the process of creating ahead-of-time (AOT) caches by streamlining the command-line options. It makes it easier for developers to adopt AOT compilation for faster startup times without dealing with complex multi-step processes.

    5.5 Ahead-of-Time Method Profiling

    Ahead-of-Time Method Profiling improves warmup time by making method-execution profiles from a previous run available immediately upon startup. This enables the JIT compiler to generate native code immediately, significantly reducing the warmup period for Java applications.

    Conclusion

    JDK 25 continues the trend of modernizing Java with features that improve developer productivity, performance, and security. The finalization of Scoped Values and the introduction of Stable Values are particularly exciting for building robust, high-performance applications.

    To stay updated with the latest updates in Java and Spring, follow us on LinkedIn and Medium.

    Summarise

    Transform Your Learning

    Get instant AI-powered summaries of YouTube videos and websites. Save time while enhancing your learning experience.

    Instant video summaries
    Smart insights extraction
    Channel tracking