# Interface LazyConstant<T>

Type Parameters:
  `T` - type of the constant

All Superinterfaces:
  `Supplier<T>`

public sealed interface LazyConstant<T> extends Supplier<T>
`LazyConstant` is a preview API of the Java platform.
Programs can only use `LazyConstant` when preview features are enabled.
Preview features may be removed in a future release, or upgraded to permanent features of the Java platform.
A lazy constant is a holder of contents that can be set at most once.

A lazy constant is created using the factory method LazyConstant.of(`<computing function>`).

When created, the lazy constant is not initialized, meaning it has no contents.

The lazy constant (of type `T`) can then be initialized (and its contents retrieved) by calling get(). The first time 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 contents can never change and will be retrieved over and over again upon subsequent get() invocations.

Consider the following example where a lazy constant field "`logger`" holds an object of type `Logger`:

    public class Component {

       // Creates a new uninitialized lazy constant
       private final LazyConstant<Logger> logger =
               LazyConstant.of( () -> Logger.create(Component.class) );

       public void process() {
           logger.get().info("Process started");
           // ...
       }
    }

Initially, the lazy constant is not initialized. When `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, get() guarantees that the constant is initialized before it returns, barring any exceptions.

Furthermore, get() guarantees that, out of several threads trying to invoke the computing function simultaneously, 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 `Logger.create()` may result in storage resources being prepared.

## Exception handling

If the computing function returns `null`, a NullPointerException is thrown. Hence, a lazy constant can never hold a `null` value. Clients who want to use a nullable constant can wrap the value into an Optional holder.

If the computing function recursively invokes itself (directly or indirectly via the lazy constant), an IllegalStateException is thrown, and the lazy constant is not initialized.

## 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 `Foo` and a `Bar` instance (that is dependent on the `Foo` instance) are lazily created, both of which are held by lazy constants:

    public final class DependencyUtil {

        private DependencyUtil() {}

        public static class Foo {
             // ...
         }

        public static class Bar {
            public Bar(Foo foo) {
                 // ...
            }
        }

        private static final LazyConstant<Foo> FOO = LazyConstant.of( Foo::new );
        private static final LazyConstant<Bar> BAR = LazyConstant.of( () -> new Bar(FOO.get()) );

        public static Foo foo() {
            return FOO.get();
        }

        public static Bar bar() {
            return BAR.get();
        }

    }

Calling `BAR.get()` will create the `Bar` singleton if it is not already created. Upon such a creation, a dependent `Foo` will first be created if the `Foo` does not already exist.

## Thread 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, after which the other threads observe the lazy constant is initialized and leave the constant unchanged and will never invoke any computation.

The invocation of the computing function and the resulting initialization of the constant happens-before the initialized constant's content is read. Hence, the initialized constant's content, including any `final` fields of any newly created objects, is safely published.

Thread interruption does not cancel the initialization of a lazy constant. In other words, if the computing thread is interrupted, `LazyConstant::get` doesn't clear the interrupted thread’s status, nor does it throw an InterruptedException.

If the computing function blocks indefinitely, other threads operating on this lazy constant may block indefinitely; no timeouts or cancellations are provided.

## Performance

The contents 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 contents and instead use the contents that has been previously observed. We call this optimization constant folding. This is only possible if there is a direct reference from a `static final` field to a lazy constant or if there is a chain from a `static final` field -- via one or more trusted fields (i.e., `static final` fields, record fields, or final instance fields in hidden classes) -- to a lazy constant.

## Miscellaneous

Except for equals(obj) and orElse(other) parameters, all method parameters must be non-null, or a `NullPointerException` will be thrown.

API Note:
  Once a lazy constant is initialized, its contents cannot ever be removed. This can be a source of an unintended memory leak. More specifically, a lazy constant strongly references it contents. Hence, the contents of a lazy constant will be reachable as long as the lazy constant itself is reachable.

  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 lazy listPREVIEW of arbitrary depth can be used, which provides constant components.

  The `LazyConstant` type is not `Serializable`.

  Use in static initializers may interact with class initialization order; cyclic initialization may result in initialization errors as described in section 12.4 of The Java Language Specification.

Implementation Note:
  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 contents may or may not be immutable (e.g., it may hold an ArrayList).
See Java Language Specification:
  12.4 Initialization of Classes and Interfaces
  17.4.5 Happens-before Order
Since:
  26
See Also:
  - `Optional`
  - `Supplier`
  - `List.ofLazy(int, IntFunction)`PREVIEW
  - `Map.ofLazy(Set, Function)`PREVIEW

- ## Method Summary

  Modifier and Type
  Method
  Description
  `boolean`
  `equals(Object obj)`
  Returns `true` if this lazy constant is the same instance as the provided `obj`, otherwise `false`.
  `T`
  `get()`
  Returns the contents of this initialized constant. If not initialized, first computes and initializes this constant using the computing function.
  `int`
  `hashCode()`
  Returns the identity hash code for this lazy constant.
  `boolean`
  `isInitialized()`
  Returns `true` if the constant is initialized, `false` otherwise.
  `static <T> LazyConstantPREVIEW<T>`
  `of(Supplier<? extends T> computingFunction)`
  Returns a lazy constant whose contents is to be computed later via the provided `computingFunction`.
  `T`
  `orElse(T other)`
  Returns the contents of this lazy constant if initialized, otherwise, returns `other`.
  `String`
  `toString()`
  Returns a string suitable for debugging.

- ## Method Details

  - ### orElse

    T orElse(T other)
    Returns the contents of this lazy constant if initialized, otherwise, returns `other`.

    This method never triggers initialization of this lazy constant and will observe initialization by other threads atomically (i.e., it returns the contents if and only if the initialization has already completed).

    Parameters:
      `other` - value to return if the content is not initialized (can be `null`)
    Returns:
      the contents of this lazy constant if initialized, otherwise, returns `other`

  - ### get

    T get()
    Returns the contents of this initialized constant. If not initialized, first computes and initializes this constant using the computing function.

    After this method returns successfully, the constant is guaranteed to be initialized.

    If the computing function throws, the throwable is relayed to the caller and the lazy constant remains uninitialized; a subsequent call to get() may then attempt the computation again.

    Specified by:
      `get` in interface `Supplier<T>`
    Returns:
      the contents of this initialized constant. If not initialized, first computes and initializes this constant using the computing function

  - ### isInitialized

    boolean isInitialized()
    Returns `true` if the constant is initialized, `false` otherwise.

    This method never triggers initialization of this lazy constant and will observe changes in the initialization state made by other threads atomically.

    Returns:
      `true` if the constant is initialized, `false` otherwise

  - ### equals

    boolean equals(Object obj)
    Returns `true` if this lazy constant is the same instance as the provided `obj`, otherwise `false`.

    In other words, equals compares the identity of this lazy constant and `obj` to determine equality. Hence, two distinct lazy constants with the same contents are not equal.

    This method never triggers initialization of this lazy constant.

    Overrides:
      `equals` in class `Object`
    Parameters:
      `obj` - the reference object with which to compare.
    Returns:
      `true` if this lazy constant is the same instance as the provided `obj`, otherwise `false`
    See Also:
      - `Object.hashCode()`
      - `HashMap`

  - ### hashCode

    int hashCode()
    Returns the identity hash code for this lazy constant. This method never triggers initialization of this lazy constant.
    Overrides:
      `hashCode` in class `Object`
    Returns:
      the identity hash code for this lazy constant
    See Also:
      - `Object.equals(java.lang.Object)`
      - `System.identityHashCode(Object)`

  - ### toString

    String toString()
    Returns 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 contents if and only if the initialization has already completed).

    If this lazy constant is initialized, an implementation-dependent string containing the Object.toString() of the contents will be returned; otherwise, an implementation-dependent string is returned that indicates this lazy constant is not yet initialized.

    Overrides:
      `toString` in class `Object`
    Returns:
      a string suitable for debugging

  - ### of

    static <T> LazyConstantPREVIEW<T> of(Supplier<? extends T> computingFunction)
    Returns a lazy constant whose contents is to be computed later via the provided `computingFunction`.

    The returned lazy constant strongly references the provided `computingFunction` at least until initialization completes successfully.

    If the provided computing function is already an instance of `LazyConstant`, the method is free to return the provided computing function directly.

    Implementation Note:
      after initialization completes successfully, the computing function is no longer strongly referenced and becomes eligible for garbage collection.
    Type Parameters:
      `T` - type of the constant
    Parameters:
      `computingFunction` - in the form of a Supplier to be used to initialize the constant
    Returns:
      a lazy constant whose contents is to be computed later via the provided `computingFunction`