/* * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.lang; import jdk.internal.javac.PreviewFeature; import jdk.internal.lang.LazyConstantImpl; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.Supplier; /** * A lazy constant is a holder of content that can be initialized at most once. *
* A lazy constant is created using the factory method
* {@linkplain LazyConstant#of(Supplier) LazyConstant.of({@code
* When created, the lazy constant is not initialized, meaning it has no content.
*
* The lazy constant (of type {@code T}) can then be initialized
* (and its content retrieved) by calling {@linkplain #get() get()}. The first time
* {@linkplain #get() get()} is called, the underlying computing function
* (provided at construction) will be invoked and the result will be used to initialize
* the constant.
*
* Once a lazy constant is initialized, its content can never change
* and will always be returned by subsequent {@linkplain #get() get()} invocations.
*
* Consider the following example where a lazy constant field "{@code logger}" holds
* an object of type {@code Logger}:
*
* {@snippet lang = java:
* public class Component {
*
* // Creates a new uninitialized lazy constant
* private final LazyConstant
* Initially, the lazy constant is not initialized. When {@code logger.get()}
* is first invoked, it evaluates the computing function and initializes the constant to
* the result; the result is then returned to the client. Hence, {@linkplain #get() get()}
* guarantees that the constant is initialized before it returns, barring
* any exceptions.
*
* Furthermore, {@linkplain #get() get()} guarantees that, out of several threads trying to
* invoke the computing function simultaneously, {@linkplain ##thread-safety only one is
* ever selected} for computation. This property is crucial as evaluation of the computing
* function may have side effects, for example, the call above to {@code Logger.create()}
* may result in storage resources being prepared.
*
*
* All failures are handled in this way. There are two special cases that cause unchecked
* exceptions to be thrown:
*
* If the computing function returns {@code null}, a {@linkplain NoSuchElementException}
* (with a {@linkplain NullPointerException} as a cause) will be thrown. Hence, a
* lazy constant can never hold a {@code null} value. Clients who want to use a nullable
* constant can wrap the value into an {@linkplain Optional} holder.
*
* If the computing function recursively invokes itself via the lazy constant, a
* {@linkplain NoSuchElementException} (with an {@linkplain IllegalStateException} as a
* cause) will be thrown.
*
*
* The invocation of the computing function and the resulting initialization of
* the constant {@linkplain java.util.concurrent##MemoryVisibility happens-before}
* the initialized constant's content is read. Hence, the initialized constant's content,
* including any {@code final} fields of any newly created objects, is safely published.
* As subsequent retrieval of the content might be elided, there are no other memory
* ordering or visibility guarantees provided as a consequence of calling
* {@linkplain #get()} again.
*
* Thread interruption does not cancel the initialization of a lazy constant. In other
* words, if the computing thread is interrupted, {@code LazyConstant::get} doesn't clear
* the interrupted thread’s status, nor does it throw an {@linkplain InterruptedException}.
*
* If the computing function blocks indefinitely, other threads operating on this
* lazy constant may block indefinitely; no timeouts or cancellations are provided.
*
*
* While it's possible to store an array inside a lazy constant, doing so will
* not result in improved access performance of the array elements. Instead, a
* {@linkplain List#ofLazy(int, IntFunction) lazy list} of arbitrary depth can
* be used, which provides constant components.
*
* The {@code LazyConstant} type is not {@link Serializable}.
*
* Use in static initializers may interact with class initialization order;
* cyclic initialization may result in initialization errors as described
* in section {@jls 12.4} of The Java Language Specification.
*
* @implNote
* A lazy constant is free to synchronize on itself. Hence, care must be
* taken when directly or indirectly synchronizing on a lazy constant.
* A lazy constant is unmodifiable but its content may or may not be
* immutable (e.g., it may hold an {@linkplain ArrayList}).
*
* @param
* If this constant is not initialized, first computes and initializes it
* using the computing function.
*
* After this method returns successfully, the constant is guaranteed to be
* initialized.
*
* If an unchecked exception is thrown when evaluating the computing function or if
* the computing function returns {@code null}, this lazy constant is not initialized
* but transitions to an error state whereafter a {@linkplain NoSuchElementException}
* is thrown as described in the {@linkplain ##exception-handling Exception handling}
* section.
*
* @throws NoSuchElementException if this lazy constant is in an error state
*/
T get();
// Object methods
/**
* {@return {@code true} if this lazy constant is the same instance as
* the provided {@code obj}, otherwise {@code false}}
*
* In other words, equals compares the identity of this lazy constant and {@code obj}
* to determine equality. Hence, two distinct lazy constants with the same content are
* not equal.
*
* This method never triggers initialization of this lazy constant.
*/
@Override
boolean equals(Object obj);
/**
* {@return the {@linkplain System#identityHashCode(Object) identity hash code} for
* this lazy constant}
*
* This method never triggers initialization of this lazy constant.
*/
@Override
int hashCode();
/**
* {@return a string suitable for debugging}
*
* This method never triggers initialization of this lazy constant and will observe
* initialization by other threads atomically (i.e., it observes the
* content if and only if the initialization has already completed).
*
* If this lazy constant is initialized, an implementation-dependent string
* containing the {@linkplain Object#toString()} of the
* content will be returned; otherwise, an implementation-dependent string is
* returned that indicates this lazy constant is not yet initialized.
*/
@Override
String toString();
// Factory
/**
* {@return a new lazy constant whose content is to be computed later via the
* provided {@code computingFunction}}
*
* The returned lazy constant strongly references the provided
* {@code computingFunction} until computation completes (successfully or with
* failure).
*
* By design, the method always returns a new lazy constant even if the provided
* computing function is already an instance of {@code LazyConstant}. Clients that
* want to elide creation under this condition can write a utility method similar
* to the one in the snippet below and create lazy constants via this method rather
* than calling the built-in factory {@linkplain #of(Supplier)} directly:
*
* {@snippet lang = java:
* static Exception handling
* If evaluation of the computing function throws an unchecked exception (i.e., a runtime
* exception or an error), the lazy constant is not initialized but instead transitions to
* an error state whereafter a {@linkplain NoSuchElementException} is thrown with the
* unchecked exception as a cause. Subsequent {@linkplain #get() get()} calls throw
* {@linkplain NoSuchElementException} (without ever invoking the computing function
* again) with no cause and with a message that includes the name of the original
* unchecked exception's class.
* Composing lazy constants
* A lazy constant can depend on other lazy constants, forming a dependency graph
* that can be lazily computed but where access to individual elements can still be
* performant. In the following example, a single {@code Foo} and a {@code Bar}
* instance (that is dependent on the {@code Foo} instance) are lazily created, both of
* which are held by lazy constants:
*
* {@snippet lang = java:
* public static class Foo {
* // ...
* }
*
* public static class Bar {
* public Bar(Foo foo) {
* // ...
* }
* }
*
* static final LazyConstantThread Safety
* A lazy constant is guaranteed to be initialized atomically and at most once. If
* competing threads are racing to initialize a lazy constant, only one updating thread
* runs the computing function (which runs on the caller's thread and is hereafter denoted
* the computing thread), while the other threads are blocked until the constant
* is initialized (or computation fails), after which the other threads observe the lazy
* constant is initialized (or has transisioned to an error state) and leave the constant
* unchanged and will never invoke any computation.
* Performance
* The content of a lazy constant can never change after the lazy constant has been
* initialized. Therefore, a JVM implementation may, for an initialized lazy constant,
* elide all future reads of that lazy constant's content and instead use the content
* that has been previously observed. We call this optimization constant folding.
* This is only possible if there is a direct reference from a {@code static final} field
* to a lazy constant or if there is a chain from a {@code static final} field -- via one
* or more trusted fields (i.e., {@code static final} fields,
* {@linkplain Record record} fields, or final instance fields in hidden classes) --
* to a lazy constant.
*
* @apiNote Once a lazy constant is initialized, its content can't be removed.
* This can be a source of an unintended memory leak. More specifically,
* a lazy constant {@linkplain java.lang.ref##reachability strongly references}
* its content. Hence, the content of a lazy constant will be reachable as long
* as the lazy constant itself is reachable.
*