What Is New in Java 25
Java 25 is a Long-Term Support (LTS) release that consolidates a significant set of language improvements, performance gains, security hardening, and monitoring capabilities. It finalizes several features that have been in preview for multiple cycles, removes long-deprecated legacy mechanisms, and delivers meaningful JVM-level optimizations that reduce memory overhead and improve startup time.
| Category | Highlights |
|---|---|
| New Features | Module import declarations (JEP 511); Compact source files and instance main methods (JEP 512); Flexible constructor bodies (JEP 513); Scoped values -- finalized (JEP 506); Key Derivation Function API (JEP 510); PEM encoding API preview (JEP 470); Stable values preview (JEP 502); ForkJoinPool implements ScheduledExecutorService; Inflater/Deflater implement AutoCloseable; HttpClient body size limiting; JFR CPU-time profiling, cooperative sampling, method timing and tracing; New SHAKE128-256 and SHAKE256-512 MessageDigest algorithms; TLS Keying Material Exporters in JSSE; SHA-3 ECDSA signature methods in XML Security |
| Improvements | Compact object headers promoted to product option (JEP 519); AOT command-line ergonomics simplified (JEP 514); AOT method profiling for faster warmup (JEP 515); G1 shared card sets reduce remembered set overhead; G1 improved Mixed GC region selection to reduce pause spikes; ZGC string deduplication skips short-lived strings; ZGC improved fragmentation handling; ML-DSA and ML-KEM performance improved 1.5--2.7x on aarch64/AVX-512; SHA-1 disabled in TLS/DTLS 1.2 handshake signatures; CLDR upgraded to version 47; jpackage no longer includes service bindings by default; javadoc syntax highlighting and improved keyboard navigation |
| Bug Fixes | Serial/Parallel GC no longer throws premature OutOfMemoryErrors due to JNI critical regions; G1 pause time spikes reduced by improved region selection; ZGC skips deduplication for young short-lived strings; XMLStreamReader now throws XMLStreamException (not EOFException) on premature EOF; javac no longer writes class files into JAR files on the classpath; Japanese Imperial Calendar now throws IllegalArgumentException for invalid ERA values; Inner class constructors now enforce non-null enclosing instance |
| Breaking Changes | Graal JIT compiler removed; Old JMX system properties removed (jmx.extend.open.types, jmx.invoke.getters, and others); PerfData periodic sampling removed along with -XX:PerfDataSamplingInterval; sun.rt._sync* performance counters removed; SunPKCS11 PBE-related SecretKeyFactory implementations removed; Expired Baltimore CyberTrust and two Camerfirma root certificates removed; java.net.Socket constructors now throw IllegalArgumentException when stream=false; File.delete on Windows no longer removes read-only attribute before deleting; JLine-based Console reverted to opt-in; jpackage no longer binds services by default |
| Deprecations | UseCompressedClassPointers deprecated for removal; VFORK process launch mechanism on Linux deprecated; java.locale.useOldISOCodes system property deprecated; JMX DescriptorSupport XML interchange deprecated for removal; Broad set of Permission classes deprecated for removal (FilePermission, RuntimePermission, SSLPermission, and many others); BasicSliderUI() no-argument constructor removed |
What language changes ship in Java 25, and which are still in preview?
Java 25 delivers a meaningful set of language improvements, but not all of them are final -- understanding the distinction matters before you enable them in production builds.
Finalized in Java 25:
- Module Import Declarations (JEP 511): You can now import all packages exported by a module with a single declaration. For example,
import module java.sql;replaces a long list of individualjava.sql.*imports. This is especially useful for scripts and utility classes that leverage standard library modules heavily. Notably, the importing code does not need to be in a module itself. - Compact Source Files and Instance Main Methods (JEP 512): Beginners and utility scripts can now write a valid Java program without declaring a class or a static main method. A top-level method
void main()is sufficient. This is a legitimate production feature, not just a teaching tool -- it simplifies small tools and internal scripts. - Flexible Constructor Bodies (JEP 513): Statements can now appear before
super(...)orthis(...)calls in constructors, provided they do not reference the object under construction. This eliminates many awkward workarounds where you previously had to compute a value in a static helper just to pass it to a superclass constructor. - Scoped Values (JEP 506): After multiple preview cycles, scoped values are now a standard API. They provide immutable, thread-contained data sharing as a safer, lower-overhead alternative to
ThreadLocal, and integrate tightly with virtual threads and structured concurrency.
Still in preview or incubator:
- Primitive Types in Patterns (JEP 507, third preview): Allows primitive types in all pattern contexts including
instanceofandswitch. Requires--enable-preview. - Structured Concurrency (JEP 505, fifth preview): Still iterating on API shape before finalization.
- Stable Values (JEP 502, preview): Objects that hold immutable data treated as JVM constants, offering
final-like optimizations with lazy initialization semantics. - PEM Encoding API (JEP 470, preview): A standard API for reading and writing PEM-encoded cryptographic objects.
- Vector API (JEP 508, tenth incubator): Still incubating pending Project Valhalla primitives.
In practice, use --enable-preview only in internal tools and experimental services; avoid preview features in shared library code that other teams depend on.
How does Java 25 improve JVM performance and startup time?
Java 25 ships several orthogonal performance improvements that together reduce memory footprint, improve GC pause predictability, and accelerate application startup -- all without code changes.
Compact Object Headers (JEP 519): This feature, introduced experimentally in JDK 24, is now a product option. Enable it with -XX:+UseCompactObjectHeaders (no longer requires -XX:+UnlockExperimentalVMOptions). It reduces the size of object headers from 128 bits to 64 bits on 64-bit JVMs, shrinking heap footprint for object-dense workloads. Two new CDS archives (classes_coh.jsa and classes_nocoops_coh.jsa) are included to preserve startup performance when this flag is on. The feature remains off by default but is a strong candidate for the default in a future release.
Ahead-of-Time improvements (JEP 514 and JEP 515): JEP 514 simplifies the commands to create AOT caches for common use cases, while JEP 515 introduces AOT method profiling -- the HotSpot JIT compiler can now use profiling data collected from a previous run to generate optimized native code immediately at startup rather than waiting for profiles to accumulate. This reduces warmup time significantly for services that restart frequently.
G1 GC improvements: Two related changes address G1 pause behavior. First, regions expected to be collected together during Mixed GC now share a single G1CardSet (remembered set structure), cutting memory overhead and merge time. Second, region selection during Mixed GC is improved using richer data from the marking phase, so regions with high inter-region reference counts that would blow the pause budget can be deferred. Watch out for changes in GC log output patterns -- pause times may be more consistent but individual Mixed GC cycles might collect fewer regions.
ZGC fragmentation: ZGC has been updated to better manage virtual address space fragmentation on large-heap deployments. Asynchronous unmapping (the last use of multi-mapped memory) has been removed, which also means RSS-reported heap usage will no longer appear inflated on systems that previously showed this behavior.
# Enable compact object headers (product feature in JDK 25)
java -XX:+UseCompactObjectHeaders -jar myapp.jar
# Create AOT cache for faster startup (simplified in JEP 514)
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -jar myapp.jar
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot -jar myapp.jar
java -XX:AOTCache=app.aot -jar myapp.jar
What security and cryptography changes does Java 25 introduce?
Java 25 delivers a substantial set of security updates, including new APIs, algorithm additions, key store changes, and a significant tightening of TLS defaults -- several of which will break connections to legacy servers or misconfigured infrastructure.
SHA-1 disabled in TLS/DTLS 1.2 handshake signatures: The algorithms rsa_pkcs1_sha1, ecdsa_sha1, and dsa_sha1 are now listed in jdk.tls.disabledAlgorithms under the usage HandshakeSignature constraint. This aligns with RFC 9155. Most production servers have moved away from SHA-1, but internal services, monitoring agents, or older appliances may still use it. Test TLS connectivity to all targets before deploying JDK 25. Re-enabling requires editing the java.security config file, which is a deliberate friction point.
Key Derivation Function API (JEP 510): A standard javax.crypto.KDF API is now available for algorithms like HKDF-SHA256, HKDF-SHA384, and HKDF-SHA512. SunPKCS11 adds support for the same HKDF variants. This matters if you are implementing protocols that derive session keys from a shared secret -- you previously had to use third-party libraries or roll your own HKDF.
TLS Keying Material Exporters: Two new methods on ExtendedSSLSession expose TLS key export per RFC 5705 and RFC 8446. This enables protocols like EAP-TLS or custom channel-binding mechanisms that need to derive application-layer keys from the TLS session:
ExtendedSSLSession session = (ExtendedSSLSession) sslSocket.getSession();
byte[] keyMaterial = session.exportKeyingMaterialData(
"EXPORTER-my-protocol", contextBytes, 32
);
Post-quantum cryptography performance: ML-DSA (module-lattice digital signature) operations are 1.5--2.5x faster, and ML-KEM (key encapsulation mechanism) operations are 1.9--2.7x faster on aarch64 and AVX-512 platforms. These algorithms were introduced earlier as part of NIST post-quantum standardization and are now practical for production TLS handshakes and signing workflows.
Permission class deprecations: A very large set of permission classes -- including FilePermission, RuntimePermission, SSLPermission, NetPermission, and many others -- are deprecated for removal. These were only meaningful with the Security Manager, which was removed in JDK 17. If you are maintaining frameworks that check or create these permissions defensively, plan to remove those paths.
Root certificate changes: The expired Baltimore CyberTrust Root and two Camerfirma roots have been removed from the cacerts trust store. Four new Sectigo roots have been added. Audit any certificate chains that anchored to the removed roots.
What breaking changes and removals in Java 25 require immediate migration attention?
Java 25 removes or changes the behavior of several long-deprecated features. Most of these have been signaled for multiple releases, but a few behavioral changes affect code that was previously working without any deprecation warning.
Graal JIT compiler removed: The optional experimental Graal JIT (enabled via -XX:+UseJVMCICompiler with the Graal module) has been removed from the JDK. Teams using GraalVM CE or EE should continue using the dedicated GraalVM distribution, which packages its own JDK. If you have CI pipelines that pass -XX:+UseJVMCICompiler, remove that flag before upgrading.
PerfData sampling removed: The StatSampler and -XX:PerfDataSamplingInterval have been removed. Heap counters for Serial and Parallel GC are now updated only post-collection, meaning sun.gc.generation.0.space.0.used (Eden space) will always read zero. Tools that scrape the PerfData file directly -- some older APM agents and custom health checks do this -- will see stale or zero data. Migrate to JFR events or JMX MBeans.
sun.rt._sync* counters removed: The object monitor perf counters are gone. Replacement JFR events: JavaMonitorEnter, JavaMonitorWait, JavaMonitorNotify, JavaMonitorInflate, JavaMonitorDeflate, JavaMonitorStatistics.
File.delete behavior change on Windows: File.delete() no longer strips the read-only DOS attribute before deleting. It now returns false for read-only files instead of silently mutating the file system. This is a silent behavior change -- no deprecation warning, no compile error. Any code that relied on this to delete read-only temp files must now call Files.setAttribute(path, "dos:readonly", false) explicitly first. The old behavior is re-enableable via -Djdk.io.File.allowDeleteReadOnlyFiles=true.
JLine Console reverted to opt-in: The JLine-based System.console() implementation, which became the default in JDK 22, has been reverted to opt-in. Interactive CLI applications using Console for rich terminal input may see reduced functionality by default. This only affects programs that use System.console() directly; most application servers are unaffected.
jpackage no longer binds services by default: Run-time images created by jpackage will include fewer modules. If your packaged application relies on service loader bindings pulled in transitively, add --bind-services explicitly to your --jlink-options:
jpackage --input lib --main-jar app.jar \
--jlink-options "--strip-native-commands --strip-debug \
--no-man-pages --no-header-files --bind-services"
ForkJoinPool and CompletableFuture behavior change: All async CompletableFuture and SubmissionPublisher methods now always use the ForkJoinPool common pool. Previously, when the common pool had parallelism less than 2, a new thread was created per task. This is a correctness fix, but it changes thread identity and context propagation behavior that some frameworks depend on. In practice, most teams will see no impact unless they customized common pool parallelism to 1 for isolation purposes.
How does Java 25 enhance observability and diagnostic tooling?
Java 25 makes JFR significantly more capable and fixes several long-standing gaps in thread dump and connection diagnostics.
JFR method timing and tracing (JEP 520): You can now annotate methods for JFR timing and tracing via bytecode instrumentation, without writing custom agents. This is a major usability improvement for profiling specific code paths in production without full profiler overhead.
JFR CPU-time profiling on Linux (JEP 509, experimental): More accurate CPU-time profiling that distinguishes CPU time from wall-clock time. This matters when profiling services on shared hosts where scheduled delays would otherwise inflate wall-clock samples. Requires Linux and is currently experimental.
JFR cooperative sampling (JEP 518): Stack walks now happen only at safepoints, which eliminates a class of JVM stability issues caused by asynchronous stack sampling. The tradeoff is slight safepoint bias, but the stability improvement makes this worthwhile for production profiling.
JFR contextual annotations: A new @jdk.jfr.Contextual annotation lets you mark fields in custom JFR events as contextual. The JFR tool will then automatically correlate those fields (such as HTTP trace IDs or span IDs) with lower-level events like lock contention and I/O that occur within the same thread. This closes a key observability gap between business-level events and JVM-level events:
@Name("com.example.HttpRequest")
@Label("HTTP Request")
class HttpRequestEvent extends Event {
@Label("URL") @Contextual
String url;
@Label("Trace ID") @Contextual
String traceId;
}
JFR default throttling changes: Socket and file I/O events (jdk.SocketRead, jdk.SocketWrite, jdk.FileRead, jdk.FileWrite) now default to a 1 ms threshold (down from 20 ms) with a rate limit of 100 events per second. The jdk.JavaExceptionThrow event is now enabled by default at 100 events per second. If you have existing JFR configurations that assume these events are off or have a 20 ms threshold, audit your .jfc files and -XX:StartFlightRecording flags before deploying to production to avoid unexpected overhead.
Thread dumps now include lock information: The HotSpotDiagnosticMXBean.dumpThreads API and jcmd Thread.dump_to_file now include lock information in their output, improving usefulness for diagnosing contention issues. Note that unlike jstack, these dumps do not yet detect deadlocks -- a known limitation in this release.
People Also Ask -- Java 25
Is Java 25 an LTS release?
Yes, Java 25 is a Long-Term Support release. Oracle and other JDK vendors will provide extended support for it, making it the primary upgrade target for teams currently on Java 17 or Java 21.
Does upgrading to Java 25 require changes to existing applications?
Most applications will continue to work, but several behavioral changes require attention -- particularly File.delete read-only behavior on Windows, the removal of sun.rt._sync performance counters, the removal of old JMX system properties, the SHA-1 TLS handshake signature restriction, and jpackage no longer including service bindings by default. Applications using Graal JIT explicitly or consuming PerfData directly will require more significant changes.
How do I enable compact object headers in Java 25?
Add -XX:+UseCompactObjectHeaders to your JVM flags -- no longer requires -XX:+UnlockExperimentalVMOptions as it did in JDK 24. For custom jlink images, also run your image's java binary with -XX:+UseCompactObjectHeaders -Xshare:dump after creation to generate the CDS archive for this mode.
Are Scoped Values and Structured Concurrency safe for production use in Java 25?
Scoped values are finalized and safe to use in production with Java 25. Structured concurrency remains in its fifth preview in Java 25, so it requires --enable-preview at compile and runtime, and its API may still change -- avoid it in shared library code or APIs you expose to other teams.
What happens to my code that uses Permission classes like FilePermission or RuntimePermission?
These classes are deprecated for removal but still compile and function in Java 25. You will see deprecation warnings. Since the Security Manager was removed in JDK 17, any code that creates or checks these permissions is effectively dead code; the recommended action is to remove those code paths entirely rather than waiting for a compile error in a future release.
Will Java 25 break TLS connections to older servers?
It can. SHA-1 in TLS 1.2 handshake signatures is now disabled by default, which will cause connections to fail if the server or client certificate chain relies on SHA-1-signed certificates in the handshake signature. Run a connectivity test suite against all upstream and downstream TLS endpoints before deploying. To re-enable on a per-deployment basis, remove the rsa_pkcs1_sha1 usage HandshakeSignature entry from jdk.tls.disabledAlgorithms in the java.security configuration file.