<i18n dev> RFR: 8366178: Implement JEP 526: Lazy Constants (Second Preview)

Chen Liang liach at openjdk.org
Mon Oct 13 11:51:04 UTC 2025


On Sat, 4 Oct 2025 14:29:08 GMT, ExE Boss <duke at openjdk.org> wrote:

>> Implement JEP 526: Lazy Constants (Second Preview)
>> 
>> The lazy list/map implementations are broken out from `ImmutableCollections` to a separate class.
>> 
>> The old benchmarks are not moved/renamed to allow comparison with previous releases.
>> 
>> `java.util.Optional` is updated so that its field is annotated with `@Stable`.  This is to allow `Optional` instances to be held in lazy constants and still provide constant folding.
>
> Getting access to the underlying `StableValue` API with **Lazy Constants** is way too hacky and convoluted (but doable):
> <details>
> <summary>StableVar.java</summary>
> 
> 
> /*
>  * Any copyright is dedicated to the Public Domain.
>  * https://creativecommons.org/publicdomain/zero/1.0/
>  */
> 
> import java.util.NoSuchElementException;
> import java.util.function.Supplier;
> 
> import org.jspecify.annotations.NullMarked;
> import org.jspecify.annotations.Nullable;
> 
> import static java.lang.System.identityHashCode;
> import static java.util.Objects.requireNonNull;
> 
> /// Horrible awful hack to get access to raw stable values in JDK 26+.
> @NullMarked
> public sealed interface StableVar<T> permits StableHacks.StableVarImpl {
> 	boolean trySet(final T contents) throws NullPointerException, IllegalStateException;
> 	@Nullable T orNull();
> 	T orElse(final T other) throws NullPointerException;
> 	T orElseThrow() throws NoSuchElementException;
> 	boolean isSet();
> 	T orElseSet(final Supplier<? extends T> supplier) throws NullPointerException, IllegalStateException;
> 	void setOrThrow(final T contents) throws NullPointerException, IllegalStateException;
> 
> 	static <T> StableVar<T> of() {
> 		return StableHacks.newInstance();
> 	}
> }
> 
> /// Encapsulates the actual implementation of `StableValue` on `LazyConstant`
> ///
> /// @author ExE Boss
> @NullMarked
> /*package*/ final @Namespace class StableHacks {
> 	private StableHacks() throws InstantiationException { throw new InstantiationException(StableHacks.class.getName()); }
> 
> 	private static final String UNSET_SUFFIX = ".unset";
> 	private static final Object UNSET = new Object() {
> 		@Override
> 		public int hashCode() {
> 			return 0;
> 		}
> 
> 		@Override
> 		public String toString() {
> 			return "unset";
> 		}
> 	};
> 
> 	private static final ScopedValue<?> SCOPE = ScopedValue.newInstance();
> 	private static final Supplier<?> SCOPE_GETTER = SCOPE::get;
> 
> 	/*package*/ static final <T> StableVarImpl<T> newInstance() {
> 		return new StableValue<>();
> 	}
> 
> 	/*package*/ sealed interface StableVarImpl<T> extends StableVar<T> {
> 	}
> 
> 	private record StableValue<T>(
> 		// Implemented as a record so that the JVM treats this as a trusted final field
> 		// even when `-XX:+TrustFinalNonStaticFields` is not set
> 		LazyConstant<T> contents
> 	) implements StableVarImpl<T> {
> 		@SuppressWarnings("unchecked")
> 		private StableValue() {
> 			this(LazyConstant.<T>of((Supplier) SCOPE_GETTER));
> 		}
> 
> 		private StableValue {
> 			if (contents.isInitialized()) throw new InternalError();
> 		}
> 
> 		@SuppressWarnings("unchecked")
> 		private fi...

Hi @ExE-Boss, this new JEP describes how this functionality will be provided in the future:

> Lazy constants cover the common, high-level use cases for lazy initialization. In the future we might consider providing stable access semantics directly, at a lower level, for reference, array, and primitive fields. This would address, for example, use cases where the computing function associated with a lazy constant is not known at construction.

This would be necessary, as there are usage patterns (such as nominal descriptors in ClassFile API) that would benefit from multiple assignment and a stable promoted read.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/27605#issuecomment-3368317631


More information about the i18n-dev mailing list