Not exactly sure why but JDK-25 is a long awaited release. Probably because it is the next LTS (or whatever it means these days), or probably because it establishes a new baseline where there is no place for SecurityManager anymore. In any case, let us talk about everything that JDK-25 bundles in, starting with the stable features first.
JEP-506: Scoped Values: introduces scoped values, which enable a method to share immutable data both with its callees within a thread, and with child threads. Scoped values are easier to reason about than thread-local variables. They also have lower space and time costs, especially when used together with virtual threads and structured concurrency.
Since the API is final now, let us take a look at it closely.
private static final ScopedValue<Object> CONTEXT = ScopedValue.newInstance(); executor.submit(() -> ScopedValue.where(CONTEXT, new Object()).run(() -> { final Object context = CONTEXT.get(); // Use 'context' }));
In simple terms, you can think of scoped values as an immutable ThreadLocals, however their true power kicks in with structured concurrency, which sadly is still in preview in JDK-25.
JEP-511: Module Import Declarations: enhances the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself.
This is pretty useful and simple enhancement that helps with imports explosion, for example:
import module jdk.jfr;
JEP-512: Compact Source Files and Instance Main Methods: evolves the Java programming language so that beginners can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, beginners can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. Experienced developers can likewise enjoy writing small programs succinctly, without the need for constructs intended for programming in the large.
It is now possible to omit some boilerplate when using the language:
void main() { IO.println("Hello, World!"); }
JEP-510: Key Derivation Function API: introduces an API for Key Derivation Functions (KDFs), which are cryptographic algorithms for deriving additional keys from a secret key and other data.
JEP-503: Remove the 32-bit x86 Port: removes the source code and build support for the 32-bit x86 port. This port was deprecated for removal in JDK 24.
JEP-514: Ahead-of-Time Command-Line Ergonomics: makes it easier to create ahead-of-time caches, which accelerate the startup of Java applications, by simplifying the commands required for common use cases.
This is really nice improvement over two-step workflow in JDK 24 (please notice a new
-XX:AOTCacheOutput
command line flag), only one step is now required:$ java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ...
As a convenience, when operating in this way the JVM creates a temporary file for the AOT configuration and deletes the file when finished. The command line to run the application stays the same:
$ java -XX:AOTCache=app.aot -cp app.jar com.example.App ...
A new environment variable,
JDK_AOT_VM_OPTIONS
, can be used to pass command-line options that apply specifically to cache creation (AOTMode=create
), without affecting the training run (AOTMode=record
). The syntax is the same as for the existing JAVA_TOOL_OPTIONS environment variable. This enables the one-step workflow to apply even in use cases where it might seem that two steps are necessary due to differences in the command-line options.JEP-513: Flexible Constructor Bodies: in the body of a constructor, allows statements to appear before an explicit constructor invocation, i.e.,
super(...)
orthis(...)
. Such statements cannot reference the object under construction, but they can initialize its fields and perform other safe computations. This change allows many constructors to be expressed more naturally. It also allows fields to be initialized before they become visible to other code in the class, such as methods called from a superclass constructor, thereby improving safety.In my opinion, this feature would greatly improve the readability of the class initialization, let us take a look at the example:
class ByteArrayInputStreamInputStream extends ByteArrayInputStream { public ByteArrayInputStreamInputStream(int size) { if (size <= 0) { throw new IllegalArgumentException("The size has to be greater than 0"); } super(new byte[size]); } }
In pre-JDK-25,
super(...)
had to be the first statement in the constructor body and we would have no choice but to implement a function to validate thesize
and return new byte array (or throw anIllegalArgumentException
exception).JEP-519: Compact Object Headers: changes compact object headers from an experimental feature (introduced in JDK 24) to a product feature. To enable this feature pass command line option:
$ java -XX:+UseCompactObjectHeaders
JEP-521: Generational Shenandoah: changes the generational mode of the Shenandoah garbage collector from an experimental feature (introduced in JDK 24) to a product feature. The generational mode could be enabled through command line flags:
$ java -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational
JEP-515: Ahead-of-Time Method Profiling: improves warmup time by making method-execution profiles from a previous run of an application instantly available, when the HotSpot Java Virtual Machine starts. This will enable the JIT compiler to generate native code immediately upon application startup, rather than having to wait for profiles to be collected.
JEP-518: JFR Cooperative Sampling: improves the stability of the JDK Flight Recorder (JFR) when it asynchronously samples Java thread stacks. Achieves this by walking call stacks only at safepoints, while minimizing safepoint bias.
There is a new event introduced,
jdk.SafepointLatency
, which records the time it takes for a thread to reach a safepoint, for example:$ java -XX:StartFlightRecording:jdk.SafepointLatency#enabled=true,filename=recording.jfr $ jfr print --events jdk.SafepointLatency recording.jfr
JEP-520: JFR Method Timing & Tracing: extends the JDK Flight Recorder (JFR) with facilities for method timing and tracing via bytecode instrumentation.
There are two new JFR events introduced,
jdk.MethodTiming
andjdk.MethodTrace
, they both accept a filter to select the methods to time and trace, couple of the examples below:$ java '-XX:StartFlightRecording:jdk.MethodTrace#filter=java.util.HashMap::resize,filename=recording.jfr' ... $ jfr print --events jdk.MethodTrace --stack-depth 20 recording.jfr
$ java '-XX:StartFlightRecording:filename=fd.jfr,method-trace=java.io.FileDescriptor::<init>java.io.FileDescriptor::close' .. $ jfr view --cell-height 5 MethodTrace fd.jfr
$ java '-XX:StartFlightRecording:method-timing=::<clinit>,filename=clinit.jfr' ... $ jfr view method-timing clinit.jfr
A filter can also name an annotation. This causes all methods bearing the annotation, and all methods in all classes bearing the annotation, to be timed or traced.
$ jcmd <pid> JFR.start method-timing=@jakarta.ws.rs.GET
It is also possible to use JMX and the JFRs RemoteRecordingStream class to configure timing and tracing over the network.
From all perspectives, the list of the finalized features that made it into JDK-25 is rock solid. But the release also bundles a number of a new experimental and preview APIs, in addition to carried over ones.
JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview): enhances pattern matching by allowing primitive types in all pattern contexts, and extend instanceof and switch to work with all primitive types. This is a preview language feature.
JEP-505: Structured Concurrency (Fifth Preview): simplifies concurrent programming by introducing an API for structured concurrency. Structured concurrency treats groups of related tasks running in different threads as single units of work, thereby streamlining error handling and cancellation, improving reliability, and enhancing observability. This is a preview API feature.
JEP-502: Stable Values (Preview): introduces an API for stable values, which are objects that hold immutable data. Stable values are treated as constants by the JVM, enabling the same performance optimizations that are enabled by declaring a field final. Compared to final fields, however, stable values offer greater flexibility as to the timing of their initialization. This is a preview API feature.
JEP-470: PEM Encodings of Cryptographic Objects (Preview): introduces an API for encoding objects that represent cryptographic keys, certificates, and certificate revocation lists into the widely-used Privacy-Enhanced Mail (PEM) transport format, and for decoding from that format back into objects. This is a preview API feature.
JEP-508: Vector API (Tenth Incubator): introduces an API to express vector computations that reliably compile at runtime to optimal vector instructions on supported CPUs, thus achieving performance superior to equivalent scalar computations.
JEP-509: JFR CPU-Time Profiling (Experimental): enhances the JDK Flight Recorder (JFR) to capture more accurate CPU-time profiling information on Linux. This is an experimental feature.
$ java -XX:StartFlightRecording:jdk.CPUTimeSample#enabled=true,filename=recording.jfr $ jfr view cpu-time-hot-methods recording.jfr
If you are interested in the subject, I would highly recommend this in-depth series of posts from Johannes Bechberger, covering every single detail of the implementation:
Besides JEPs, JDK-25 has plenty of enhancements across the board, including bugfixes and changes in the behavior that may affect the existing applications.
-
JDK-8350441: ZGC: Overhaul Page Allocation: ZGC had been improved to better deal with virtual address space fragmentation. This is especially impactful for programs with a large heap, where virtual address space fragmentation could be a noticeable issue.
-
JDK-8192647: GClocker induced GCs can starve threads requiring memory leading to OOME: Serial and Parallel garbage collectors now ensure that no Java threads are in a JNI critical region before initiating a garbage collection eliminating unnecessary
OutOfMemoryError
s. -
JDK-8346920: Serial: Support allocation in old generation when heap is almost full: restores the support for allocation in old-gen when heap is almost full, detected as non-empty young-gen after full gc, which was removed by mistake in JDK-8333786.
-
JDK-8343782 - G1: Use one G1CardSet instance for multiple old gen regions: the G1 garbage collector further reduces remembered set memory overhead and pause-time by allowing multiple regions to share a single internal structure (G1CardSet) when they are likely to be collected together during a Mixed GC.
-
JDK-8351405 - G1: Collection set early pruning causes suboptimal region selection: the G1 garbage collector now addresses pause time spikes during Mixed GCs by improving the selection of memory regions to reclaim during those. Regions that are expected to be costly to collect due to high inter-region references may be excluded during this region selection.
-
JDK-8356848: Separate Metaspace and GC printing: information about Metaspace had been moved away from heap logging.
-
JDK-8164714: Constructor.newInstance creates instance of inner class with null outer class: inner classes must not have
null
as their immediately enclosing instance. -
JDK-8350753: Deprecate UseCompressedClassPointers: the
UseCompressedClassPointers
option had deprecated and will be removed in a future Java version. -
JDK-8338675: javac shouldn't silently change .jar files on the classpath: under some conditions,
javac
could have modified JAR or ZIP files places on the classpath, by writing classfile(s) to them. -
JDK-8345432: (ch, fs) Replace anonymous Thread with InnocuousThread: the default thread pool for the system-wide default AsynchronousChannelGroup had been changed to create threads that do not inherit anything from threads that initiate asynchronous I/O operations.
-
JDK-8354276: Strict HTTP header validation: the java.net.http.HttpClient now rejects HTTP/2 responses that contain header fields prohibited by the HTTP/2 specification (RFC-9113).
-
JDK-8341402: BigDecimal's square root optimization: the method java.math.BigDecimal::sqrt had been reimplemented to perform much better. However, in some very rare and quite artificial cases involving powers of 100 and huge precisions, the new implementation throws whereas the old one returns a result.
-
JDK-8138614: StringBuffer and StringBuilder methods improperly require "new" String to be returned: the specifications of the
substring
,subSequence
, andtoString
methods of the java.lang.StringBuilder and java.lang.StringBuffer classes had been changed not to require a new java.lang.String instance to be returned every time. -
JDK-8024695: new File("").exists() returns false whereas it is the current working directory: the java.io.File class had been changed so that an instance of File created from the empty abstract pathname (
""
) now behaves consistently like a File created from the current user directory. -
JDK-8355954: File.delete removes read-only files (win): java.io.File::delete had been changed on Windows so that it now fails and returns
false
for regular files when the DOS read-only attribute is set. -
JDK-8350880: (zipfs) Add support for read-only zip file systems: the ZIP file system provider had been updated to allow a ZIP file system be created as a read-only or read-write file system.
-
JDK-8350703: Add standard system property stdin.encoding: a new system property,
stdin.encoding
, had been added. This property contains the name of the recommended Charset for reading character data from System.in. -
JDK-8322810: Lambda expression types can't be classes: prior to JDK-25, the
javac
could have compiled lambda expressions assigned to intersection types, even if one of the types is a class, not an interface. This frequently led to bytecode being generated that raises a LambdaConversionException when executed. In JDK-25, the code like in the snippet below is not accepted by the compiler anymore:class Test { void m() { Test r = (Test & Runnable) () -> System.out.println("Hello, World!"); } }
-
JDK-8346948: Update CLDR to Version 47.0: upgrades the CLDR data in the JDK to version 47.0.
Moving on to the standard library, JDK-25 delivers rather moderate changes, but quite handy nonetheless. Let us take a look at those.
-
The addition of a new javax.sound.SoundClip class comes as a surprise.
-
A new class java.lang.IO was added to the standard library that provides convenient access to System.in and System.out for line-oriented input and output.
-
In scope of JDK-8225763: Inflater and Deflater should implement AutoCloseable, both java.util.zip.Deflater and java.util.zip.Inflater implement java.lang.AutoCloseable.
-
The java.io.Reader class has two new very convenient methods:
-
In scope of JDK-8343110, a new default method was added to java.lang.CharSequence interface:
-
In scope of JDK-8343110, a new default method was added to java.nio.CharBuffer class:
-
A java.lang.Math class was enhanced with a number of methods:
- static int powExact(int x, int n)
- static long powExact(long x, int n)
- static int unsignedMultiplyExact(int x, int y)
- static long unsignedMultiplyExact(long x, int y)
- static long unsignedMultiplyExact(long x, long y)
- static int unsignedPowExact(int x, int n)
- static long unsignedPowExact(long x, int n)
-
Similarly, mirrored changes went into java.lang.StrictMath class:
- static int powExact(int x, int n)
- static long powExact(long x, int n)
- static int unsignedMultiplyExact(int x, int y)
- static long unsignedMultiplyExact(long x, int y)
- static long unsignedMultiplyExact(long x, long y)
- static int unsignedPowExact(int x, int n)
- static long unsignedPowExact(long x, int n)
-
The java.lang.reflect.AccessFlag enum got a new method:
-
In scope of JDK-8350279: HttpClient: Add a new HttpResponse method to identify connections, the java.net.http.HttpResponse interface was enriched with one new default method:
-
As part of JDK-8328919: Add BodyHandlers / BodySubscribers methods to handle excessive server input, the following new APIs have been added:
To java.net.http.HttpResponse$BodyHandlers class:
-
A new method was added to java.util.Currency class:
-
A couple of new methods were added to java.util.TimeZone class:
-
The class javax.net.ssl.ExtendedSSLSession got some attention as well:
-
Probably, the largest change in years comes to java.util.concurrent.ForkJoinPool, which now implements java.util.concurrent.ScheduledExecutorService as part of JDK-8319447: Improve performance of delayed task handling:
- ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
- <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)
- ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
- ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
- <V>ForkJoinTask<V> submitWithTimeout(Callable<V> callable, long timeout, TimeUnit unit, Consumer<? super ForkJoinTask<V>> timeoutAction)
- long getDelayedTaskCount()
- void cancelDelayedTasksOnShutdown()
-
In scope of JDK-8351594: JFR: Rate-limited sampling of Java events, a new annotation @jdk.jfr.Throttle was introduced.
Please note that in JDK-25, the JFR events
jdk.SocketRead
,jdk.SocketWrite
,jdk.FileRead
, andjdk.FileWrite
are throttled by default. To restore previous behavior, please use-XX:StartFlightRecording:jdk.SocketRead#threshold=20ms,jdk.SocketRead#throttle=off
.Also, the
jdk.JavaExceptionThrow
event was previously disabled by default, but is now enabled by default with a rate limit of 100 events per second. To disable this event, please use-XX:StartFlightRecording:jdk.JavaExceptionThrow#enabled=false
. -
One more for JFR, as part of JDK-8356698: JFR: @Contextual, a new annotation @jdk.jfr.Contextual was introduced.
With respect to security, there are a few changes worth mentioning:
-
JDK-8354305: SHAKE128-256 and SHAKE256-512 as MessageDigest Algorithms: adds SHAKE128 and SHAKE256 as MessageDigest algorithms.
-
JDK-8350689: Turn on timestamp and thread metadata by default for java.security.debug: enhances the security debug logs by making sure that the thread and timestamp data is always present.
-
JDK-8345431: Improve jar --validate to detect duplicate or invalid entries: the command now also checks if there are duplicate entries or inconsistent headers.
-
JDK-8348986: Improve coverage of enhanced exception messages: networking exception messages can be filtered to remove sensitive information.
-
JDK-8340321: Disable SHA-1 in TLS/DTLS 1.2 handshake signatures: the use of SHA-1 in TLS & DTLS 1.2 digital signatures is disabled, following the RFC-9155 deprecations.
-
The work on phasing out the SecurityManager related functionality is underway with terminal deprecations:
- JDK-8348967: Deprecate security permission classes for removal
- JDK-8353641: Deprecate core library permission classes for removal
- JDK-8353642: Deprecate URL::getPermission method and networking permission classes for removal
- JDK-8353856: Deprecate FlighRecorderPermission class for removal
- JDK-8347985: Deprecate java.management Permission classes for removal
- JDK-8351224: Deprecate com.sun.tools.attach.AttachPermission for removal
- JDK-8351310: Deprecate com.sun.jdi.JDIPermission for removal
Last but not least, few regressions slipped into JDK-25 at the last moment, please be aware of those:
-
JDK-8367031: [backout] Change java.time month/day field types to 'byte': regression in serialization of LocalDate class objects.
-
JDK-8366434: THP not working properly with G1 after JDK-8345655:
-XX:+UseTransparentHugePages
Fails to Enable Huge Pages for G1. -
JDK-8358535: Changes in ClassValue (JDK-8351996) caused a 1-9% regression in Renaissance-PageRank: performance regression in java.lang.ClassValue::get.
My personal retrospective on the JDK-25 release, among many other things, highlights a significant progress of the Project Leyden and substantial investments into JDK Flight Recorder (JFR) tooling and instrumentation. Let us see what comes next, the lineup for JDK-26 already looks exciting.
I πΊπ¦ stand πΊπ¦ with πΊπ¦ Ukraine.
No comments:
Post a Comment