Sunday, October 11, 2026

Java 25 New Features: The Complete Guide (2025 LTS)

Java 25 New Features: The Complete Guide (2025 LTS)


LTS Release 19 JEPs September 16, 2025

Java 25 is the new Long-Term Support release (after 8, 11, 17, 21) — the version most enterprises will standardize on for years, with support until at least 2030.


Java 25 New Features: The Complete Guide (2025 LTS)



⚡ TL;DR — The Headline Features

Most important new features in Java 25 at a glance
FeatureStatusWhy it matters
Compact source files & instance main (JEP 512)✅ Finalvoid main() — Java is beginner-friendly now
Module import declarations (JEP 511)✅ Finalimport module java.base;
Flexible constructor bodies (JEP 513)✅ FinalCode before super()
Scoped Values (JEP 506)✅ FinalModern ThreadLocal replacement
Compact Object Headers (JEP 519)✅ Product~10–20% heap memory savings
Structured Concurrency (JEP 505)🔶 Preview (5th)Simplified concurrent task management
Stable Values (JEP 502)🔶 PreviewLazy init with final-field performance
KDF API (JEP 510)✅ FinalStandardized key derivation (HKDF)

📦 Full JEP List (All 19)

Every JDK Enhancement Proposal shipped in Java 25
JEPTitleStatus
470PEM Encodings of Cryptographic ObjectsPreview
502Stable ValuesPreview
503Remove the 32-bit x86 PortRemoval
504Remove the Applet APIRemoval
505Structured ConcurrencyFifth Preview
506Scoped ValuesFinal
507Primitive Types in Patterns, instanceof, and switchThird Preview
508Vector APITenth Incubator
509JFR CPU-Time ProfilingExperimental
510Key Derivation Function APIFinal
511Module Import DeclarationsFinal
512Compact Source Files and Instance Main MethodsFinal
513Flexible Constructor BodiesFinal
514AOT Command-Line ErgonomicsProduct
515AOT Method ProfilingProduct
518JFR Cooperative SamplingProduct
519Compact Object HeadersProduct
520Method TracingProduct
521Generational ShenandoahProduct

🚀 1. Language Features

1.1 Compact Source Files & Instance Main Methods (JEP 512) — Final

The biggest "Java for beginners" improvement since Java's creation.

Before (Java ≤ 24):

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Java 25:

// Hello.java — no class declaration, no static, no String[] args
void main() {
    IO.println("Hello, World!");
}
$ java Hello.java
Hello, World!

Key points:

  • A file without a class declaration is an implicit class; top-level fields and methods become its members.
  • main can be instance or static, and non-public.
  • New java.lang.IO class: IO.println(...), IO.print(...), IO.readln(prompt) — simple console I/O, available everywhere (it's in java.lang).
⚠️ Compact source files no longer implicitly import all of java.base (a change from earlier previews) — use import module java.base; if you want that.

A slightly bigger example:

// Greet.java
import module java.base;          // imports every java.base package

void main() {
    String name = IO.readln("What's your name? ");
    var greetings = Stream.of("Hello", "Bonjour", "Hola")
                          .map(g -> g + ", " + name + "!")
                          .toList();
    greetings.forEach(IO::println);
}

1.2 Module Import Declarations (JEP 511) — Final

Import all packages exported by a module in one line:

import module java.base;   // List, Map, Stream, Path, Instant, etc.
import module java.sql;    // Connection, ResultSet, ... (+ transitive exports)
  • Greatly reduces import boilerplate.
  • Name collisions are resolved by preferring explicit single-type imports (import java.util.List; beats the module import) or fully qualified names.
  • Works in regular classes, compact source files, and inside modules (respects module boundaries).

1.3 Flexible Constructor Bodies (JEP 513) — Final

Statements are now allowed before super(...) / this(...) — as long as they don't touch the instance being constructed ("early construction context").

Validate arguments before the super call:

class Employee extends Person {
    Employee(String name, int salary) {
        if (salary < 0) {                          // ✅ now legal!
            throw new IllegalArgumentException("negative salary");
        }
        super(name);                               // must still be reached exactly once
        // ... normal construction continues
    }
}

Safely initialize your own fields first (fixes the "leaking this" bug class):

class Sub extends Super {
    final int x;

    Sub(int x) {
        this.x = x;     // ✅ field initialized BEFORE super()
        super();        // Super's constructor calls overriddenMethod()
    }

    @Override
    void overriddenMethod() {
        System.out.println(x);   // safe: x is already set
    }
}

Rules in the early construction context:

  • ✅ Allowed: local variables, argument checks, static method calls, computing super() arguments, assigning own fields, even try/catch around super().
  • ❌ Not allowed: reading own fields, calling instance methods, passing this anywhere, synchronized.

1.4 Primitive Types in Patterns, instanceof, and switch (JEP 507) — Third Preview 🔶

// instanceof with primitive patterns (unboxing + safe conversion, checked at runtime)
Object o = 42;
if (o instanceof int i) {
    IO.println(i * 2);           // 84
}

// Unconditional primitive patterns make switch exhaustive
String gear(int speed) {
    return switch (speed) {
        case 0                    -> "parked";
        case int i when i < 20    -> "slow";
        case int i when i < 60    -> "cruising";
        case int i                -> "fast";
    };
}

Requires --enable-preview.

📚 2. Library & API Features

2.1 Scoped Values (JEP 506) — Final ⭐

The modern, safer replacement for ThreadLocal — built for virtual threads and structured concurrency.

public class Auth {
    static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();

    public static void main(String[] args) throws Exception {
        // Bind for a limited scope; automatically unbound afterwards
        String result = ScopedValue.where(CURRENT_USER, "alice")
                                   .call(Auth::handleRequest);
        IO.println(result);
    }

    static String handleRequest() {
        return "Processing as " + CURRENT_USER.get();   // read anywhere below
    }
}

Why prefer it over ThreadLocal:

  • Immutable & bounded — a value is set for a well-defined block, then gone.
  • Cheap inheritance — values are visible in threads forked via StructuredTaskScope (no InheritableThreadLocal copying).
  • Optimized for millions of virtual threads (immutable snapshots, no per-thread mutation).

2.2 Structured Concurrency (JEP 505) — Fifth Preview 🔶

New API shape in this preview: scopes are opened via StructuredTaskScope.open(...) with Joiners.

Response handle() throws InterruptedException {
    try (var scope = StructuredTaskScope.open()) {          // default: all must succeed
        Subtask<User>   user  = scope.fork(() -> findUser());
        Subtask<Order>  order = scope.fork(() -> fetchOrder());

        scope.join();   // waits for both; if one fails, the other is cancelled

        return new Response(user.get(), order.get());
    }
}

Other joiner strategies:

// First success wins (fan-out to replicas), others cancelled
try (var scope = StructuredTaskScope.open(Joiner.<String>anySuccessfulResultOrThrow())) {
    scope.fork(() -> fetchFromPrimary());
    scope.fork(() -> fetchFromBackup());
    return scope.join();   // first successful result; FailedException if all fail
}
  • Joiner.awaitAll() — wait for everything regardless of outcome.
  • Timeouts and thread factories configurable via the scope configuration.
  • Tasks run on virtual threads; failure cancels siblings automatically — no leaked/orphaned threads.
  • Still needs --enable-preview, but the design is expected to be near-final.

2.3 Stable Values (JEP 502) — Preview 🔶

Lazy initialization with the performance of final fields (the JIT can constant-fold them), replacing double-checked locking hacks.

public class PaymentService {
    private static final StableValue<HttpClient> CLIENT = StableValue.of();

    static HttpClient client() {
        return CLIENT.orElseSet(() -> HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(2))
                .build());          // created once, lazily, thread-safe, JIT-friendly
    }
}

Memoization helpers:

static final List<StableValue<Long>> CACHE = StableValue.list(100);

static long fib(int n) {
    if (n < 2) return n;
    return CACHE.get(n).orElseSet(() -> fib(n - 1) + fib(n - 2));
}

static final Function<Integer, Long> FIB_F = StableValue.function(100, Main::fib);

2.4 Key Derivation Function API (JEP 510) — Final

Standard API for HKDF etc. (previously each provider rolled its own):

import javax.crypto.KDF;
import javax.crypto.spec.HKDFParameterSpec;

KDF hkdf = KDF.getInstance("HKDF-SHA256");

SecretKey aesKey = hkdf.deriveKey("AES",
        HKDFParameterSpec.ofExtract()
            .addIKM(inputKeyingMaterial)
            .addSalt(salt)
            .thenExpand(info, 32));   // 32 bytes → AES key

2.5 PEM Encodings of Cryptographic Objects (JEP 470) — Preview 🔶

First-class read/write support for PEM (the ubiquitous -----BEGIN...----- format):

String pem = PEMEncoder.of().encodeToString(privateKey);

String encrypted = PEMEncoder.of()
        .encodeToString(privateKey, "passphrase".toCharArray());

PrivateKey key = PEMDecoder.of()
        .decodeFromString(encrypted, "passphrase".toCharArray());

2.6 Vector API (JEP 508) — Tenth Incubator

import jdk.incubator.vector.*;

static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;

void compute(float[] a, float[] b, float[] c) {
    for (int i = 0; i < a.length; i += SPECIES.length()) {
        var m  = SPECIES.indexInRange(i, a.length);
        var va = FloatVector.fromArray(SPECIES, a, i, m);
        var vb = FloatVector.fromArray(SPECIES, b, i, m);
        va.mul(va).add(vb.mul(vb)).neg().intoArray(c, i, m);
    }
}

Run with --add-modules jdk.incubator.vector. Still incubating pending Valhalla's value classes.

⚙️ 3. JVM, GC & Performance

3.1 Compact Object Headers (JEP 519) — Product ⭐

Reduces the object header from 96/128 bits to 64 bits → typically 10–20% less heap (more on small-object-heavy workloads). Works with all GCs.

java -XX:+UseCompactObjectHeaders -jar app.jar

3.2 Generational Shenandoah (JEP 521) — Product

Shenandoah (low-pause GC) now separates young/old objects → better throughput and shorter pauses for allocation-heavy apps.

java -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -jar app.jar

3.3 AOT: Command-Line Ergonomics (JEP 514) + Method Profiling (JEP 515)

Project Leyden's ahead-of-time cache got much simpler — startup and warmup get faster:

# One command: runs a training pass, records, and writes the cache
java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.Main

# Subsequent runs pick the cache up automatically (JEP 515 stores JIT method
# profiles in it too, so hot methods compile sooner)
java -cp app.jar com.example.Main

3.4 JFR Improvements (JEPs 509, 518, 520)

  • CPU-Time Profiling (experimental, Linux): samples running threads using CPU-time clocks — accurate profiles without safepoint bias.
  • Cooperative Sampling: safer, more reliable stack sampling for execution samples.
  • Method Tracing: trace/timing of selected methods via JFR events (jdk.MethodTiming, jdk.MethodTrace) — no agents or bytecode instrumentation:
java -XX:StartFlightRecording=filename=rec.jfr,jdk.MethodTiming#enabled=true -jar app.jar
jfr view rec.jfr        # or inspect in JMC

🗑️ 4. Removals & Cleanup

APIs and features removed or changed in Java 25
Removed / changedNotes
32-bit x86 port (JEP 503)Deprecated in 24, now gone
Applet API (JEP 504)java.applet, JApplet, etc. finally removed (deprecated since 17)
Security ManagerPermanently disabled since Java 24 (JEP 486)
Non-generational ZGCRemoved in Java 24 (JEP 490) — ZGC is generational-only now
sun.misc.Unsafe memory-access methodsWarn on use since 24 (JEP 498) — migrate to VarHandles/FFM
JNIIllegal native access warnings since 24 (JEP 472) — prepare for future restrictions

🚩 5. Flags Cheat Sheet

JVM/javac flags required for Java 25 features
FeatureFlag(s) needed
Preview features (Stable Values, PEM, primitive patterns, structured concurrency)javac --release 25 --enable-preview + java --enable-preview
Vector API--add-modules jdk.incubator.vector
Compact object headers-XX:+UseCompactObjectHeaders
Generational Shenandoah-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational
AOT cache-XX:AOTCacheOutput=app.aot (creation), auto-detected after

🔄 6. Upgrading to Java 25

From Java 21 (previous LTS) you additionally get: stream gatherers, unnamed variables (_), the FFM API, scoped values, class-file API, markdown javadoc, compact source files, module imports, flexible constructor bodies, compact object headers, AOT cache, the virtual-thread synchronized pinning fix (from 24), and everything above.

From Java 17 you also get: virtual threads, sequenced collections, record patterns & pattern matching for switch, and more.

Build tooling:

<!-- Maven -->
<properties>
    <maven.compiler.release>25</maven.compiler.release>
</properties>
// Gradle
java { toolchain { languageVersion = JavaLanguageVersion.of(25) } }
# Install via SDKMAN
sdk install java 25-tem     # Eclipse Temurin 25 (or 25-oracle, 25-graal, ...)

🔮 7. What's Next (Java 26+, March 2026)

Watch for finalization of structured concurrency, stable values, and primitive patterns; continued Project Leyden work; Valhalla value classes (which will unlock the Vector API); and more FFM/JNI hardening.

💡 Note: Java 25 preview features (--enable-preview) can still evolve in future releases, so double-check the official JDK 25 release notes / JEP pages for the exact final API signatures before pinning production code to them.

❓ Frequently Asked Questions

Is Java 25 an LTS release?

Yes. Java 25, released September 16, 2025, is a Long-Term Support (LTS) release, following Java 8, 11, 17, and 21. Oracle and other vendors support it until at least 2030.

What are the biggest new features in Java 25?

The headline features are compact source files with instance main methods (JEP 512), module import declarations (JEP 511), flexible constructor bodies (JEP 513), finalized Scoped Values (JEP 506), Compact Object Headers for memory savings (JEP 519), and simpler AOT caches for faster startup (JEP 514/515).

How do I enable preview features in Java 25?

Compile with javac --release 25 --enable-preview and run with java --enable-preview. Preview features include Stable Values, PEM encodings, primitive patterns, and structured concurrency.

What is the difference between Java 21 and Java 25?

Moving from Java 21 to Java 25 adds stream gatherers, unnamed variables, the Foreign Function & Memory API, scoped values, the class-file API, compact source files, module imports, flexible constructor bodies, compact object headers, AOT caching, and the virtual-thread synchronized pinning fix.

Is Java 25 free to use?

Yes. OpenJDK builds (e.g., Eclipse Temurin, Amazon Corretto) are free, and Oracle JDK 25 is free for production under the No-Fee Terms and Conditions (NFTC).

No comments:

Post a Comment