Introduction
StableValue
is a new feature introduced in the preview version of JDK 25, aimed at improving the handling of immutable objects in Java. This innovation allows certain dynamic values to be treated as constants, offering performance optimizations similar to final
fields, while providing greater flexibility regarding when they are initialized.
The JEP related to this evolution is JEP-502, with the following defined objectives:
- Improve Java application startup time by fragmenting the monolithic initialization of application state.
- Decouple the creation of stable values from their initialization, without significant performance penalties.
- Ensure stable values are initialized at most once, even in multi-threaded programs.
- Allow user code to safely benefit from constant folding1 optimizations, just like variables declared as
final
.
What is a Stable Value?
|
|
A StableValue
is an object encapsulating immutable data. Unlike final
fields, which must be initialized upon object or class creation, Stable Values can be initialized on demand, after their declaration. This means they are only defined when their value is needed, which can improve startup performance of Java applications by avoiding loading the application’s complete state at startup.
Usage Examples
All following examples are taken from the official JavaDoc2.
Here’s a simple example of using StableValue
in an OrderController
class.
Classic Version:
|
|
In this version, the logger is automatically instantiated each time an instance of the OrderController
class is created. This could result in slower instantiation of this class, since we can imagine that creating this logger might be relatively slow (if it requires reading a config file for example, or preparing an output file for logs…).
StableValue Version:
|
|
In this example, the logger
field is a StableValue
. It is initialized only when the getLogger()
method is called for the first time. This allows delaying the costly initialization of the logger until it is actually needed.
Stable Function
StableValue
lays the foundation for higher-level abstractions. For example, a supplier
allows producing a value and caching its result:
|
|
Note that in this case, there is no accessor to the logger compared to the previous example, which makes its use more elegant.
Stable Collection
Similarly, it is possible to create stable Collection
s, whose values are calculated on first access:
|
|
Note: The JVM will directly transform this value to 16 after a few execution cycles, thanks to constant folding.
Composition
Finally, it is also possible to compose Stable Values, which allows for lazy evaluation of objects:
|
|
Calling bar()
will create the Bar
singleton if it doesn’t already exist. During this creation, the dependent Foo
will first be created if Foo
does not already exist.
Thread Safety
The content of a stable value is guaranteed to be defined at most once. If multiple threads compete to define a stable value, only one update succeeds (the first thread that manages to initialize the value), while other updates are blocked until the stable value is defined.
Try It Yourself
To try this feature, download jdk25 then compile and run your program by enabling previews:
|
|
Conclusion
Stable Values represent a particularly interesting mechanism in the management of immutable objects in Java. By offering delayed initialization and performance optimizations, they allow developers to create more efficient and responsive applications.
Constant folding with javac and with the JIT ↩︎
https://cr.openjdk.org/~pminborg/stable-values2/api/java.base/java/lang/StableValue.html ↩︎