[javaone 2025] sneak peak at the stable values API

Speaker: Per Minborg

See the table of contents for more posts


Like Schrödinger’s Cat, find out if immutable when look

General

  • StableValue – class in JDK
  • JEP 502 – stable values. Maybe preview in Java 25
  • Deferred Shallow Immutability.
  • Significant performance gains
  • Codes like lazy initialization; performs like a constant

Motivation

  • Why create object up front (ex: static) if might not need it
  • Singleton pattern needs synchronization to be correct, Showed double checked locking singleton initialization. Easy to get wrong. For example, if you don’t use volatile, can read partially initialized field.
  • With array, volatile doesn’t help becasuse elements aren’t volatile so need method handle to make volatile
  • These solutions are a bunch off code even if you get them right.

StableValue

  • Generic class. Create as empty: private final StableValue<Logger> logger = StableValue.of()
  • Use logger.orElseSet(() -> Logger.create(X.class) – API guarantees this lambda will be only called once
  • StableValue guaranteed to not change value
  • Better to use Supplier: static final Supplier<X> SUPPLIER = StableValue.supplier(X::new) and then just call SUPPLIER.get()
  • StableValue.list(SIZE, _ -> new X()) – immutable list
  • IntFunction<X> FUNC = StableValue.intFunction(size, _ -> new X()) – creates multiple singletons. Pass index to get that singleton to use.
  • Function<Integer, Double> F = StableValue.function(Set.of(1, 2, 3), i -> i*2))
  • StableValue.map(Set.of(1, 2, 3), i -> i*2))
  • List<Integer> LIST = StableValue.list(SIZE, x -> y)

Notes

  • Fibonacci sequence is no longer exponential. Figures out values as need them. Way faster
  • Why called stable and not lazy – because lazy is only one of the properties
  • Don’t have to make static, but faster if do
  • Stable value for record is much faster than for class because guaranteed to be immutable

StableContainer

  • StableContainer COMPONENTS = StableContainer.of(providers…) – this isn’t in the JEP so not sure if this is a local interface

Deferred Immutability

  • Mutable – non final
  • Stable (Stablevalue) – can update anywhere. if two threads updated, the winner sets the value and then becomes constant
  • Immutable – final – can only update in constructor/class initializer

My take

Nice to get a preview into the future. This was not an API I had heard of. Maybe because it isn’t even in preview yet.