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.
⚡ TL;DR — The Headline Features
| Feature | Status | Why it matters |
|---|---|---|
Compact source files & instance main (JEP 512) | ✅ Final | void main() — Java is beginner-friendly now |
| Module import declarations (JEP 511) | ✅ Final | import module java.base; |
| Flexible constructor bodies (JEP 513) | ✅ Final | Code before super() |
| Scoped Values (JEP 506) | ✅ Final | Modern 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) | 🔶 Preview | Lazy init with final-field performance |
| KDF API (JEP 510) | ✅ Final | Standardized key derivation (HKDF) |
📦 Full JEP List (All 19)
| JEP | Title | Status |
|---|---|---|
| 470 | PEM Encodings of Cryptographic Objects | Preview |
| 502 | Stable Values | Preview |
| 503 | Remove the 32-bit x86 Port | Removal |
| 504 | Remove the Applet API | Removal |
| 505 | Structured Concurrency | Fifth Preview |
| 506 | Scoped Values | Final |
| 507 | Primitive Types in Patterns, instanceof, and switch | Third Preview |
| 508 | Vector API | Tenth Incubator |
| 509 | JFR CPU-Time Profiling | Experimental |
| 510 | Key Derivation Function API | Final |
| 511 | Module Import Declarations | Final |
| 512 | Compact Source Files and Instance Main Methods | Final |
| 513 | Flexible Constructor Bodies | Final |
| 514 | AOT Command-Line Ergonomics | Product |
| 515 | AOT Method Profiling | Product |
| 518 | JFR Cooperative Sampling | Product |
| 519 | Compact Object Headers | Product |
| 520 | Method Tracing | Product |
| 521 | Generational Shenandoah | Product |
🚀 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.
maincan be instance or static, and non-public.- New
java.lang.IOclass:IO.println(...),IO.print(...),IO.readln(prompt)— simple console I/O, available everywhere (it's injava.lang).
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/catcharoundsuper(). - ❌ Not allowed: reading own fields, calling instance methods, passing
thisanywhere,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(noInheritableThreadLocalcopying). - 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 key2.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.jar3.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.jar3.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.Main3.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
| Removed / changed | Notes |
|---|---|
| 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 Manager | Permanently disabled since Java 24 (JEP 486) |
| Non-generational ZGC | Removed in Java 24 (JEP 490) — ZGC is generational-only now |
sun.misc.Unsafe memory-access methods | Warn on use since 24 (JEP 498) — migrate to VarHandles/FFM |
| JNI | Illegal native access warnings since 24 (JEP 472) — prepare for future restrictions |
🚩 5. Flags Cheat Sheet
| Feature | Flag(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.
--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