Class Lazy<T>

java.lang.Object
dmx.fun.Lazy<T>
Type Parameters:
T - the type of the lazily evaluated value

@NullMarked public final class Lazy<T> extends Object
A lazily evaluated value that is computed at most once.

The supplier passed to of(Supplier) is not invoked until the first call to get(). Subsequent calls return the cached result without invoking the supplier again. Memoization is thread-safe: the supplier is guaranteed to be called at most once even under concurrent access.

This type is @NullMarked: the supplier must return a non-null value. Use Lazy<Option<T>> to model a lazily evaluated optional result.

  • Method Details

    • of

      public static <T> Lazy<T> of(Supplier<? extends T> supplier)
      Creates a new Lazy that will evaluate supplier on the first call to get().
      Type Parameters:
      T - the type of the value
      Parameters:
      supplier - the supplier to evaluate lazily; must not be null
      Returns:
      a new, unevaluated Lazy<T>
      Throws:
      NullPointerException - if supplier is null
    • get

      public T get()
      Returns the value, evaluating the supplier on the first call and caching the result.

      The supplier is called at most once. All subsequent calls return the cached value. This method is thread-safe.

      Returns:
      the (possibly cached) value; never null
      Throws:
      NullPointerException - if the supplier returns null
    • isEvaluated

      public boolean isEvaluated()
      Returns true if the supplier has already been evaluated.
      Returns:
      true after the first call to get(), false before
    • map

      public <R> Lazy<R> map(Function<? super T, ? extends R> f)
      Returns a new Lazy that applies f to this value when evaluated.

      The mapping function is not invoked until get() is called on the returned Lazy. Evaluating the returned Lazy also evaluates this one.

      Type Parameters:
      R - the type of the mapped value
      Parameters:
      f - the mapping function; must not be null and must not return null
      Returns:
      a new, unevaluated Lazy<R>
      Throws:
      NullPointerException - if f is null
    • flatMap

      public <R> Lazy<R> flatMap(Function<? super T, Lazy<? extends R>> f)
      Returns a new Lazy by applying f to this value and flattening the result.

      Neither this value nor the function is evaluated until get() is called on the returned Lazy.

      Type Parameters:
      R - the type of the resulting value
      Parameters:
      f - a function that returns a Lazy<R>; must not be null
      Returns:
      a new, unevaluated Lazy<R>
      Throws:
      NullPointerException - if f is null or returns null
    • toOption

      public Option<T> toOption()
      Evaluates this Lazy and wraps the result in an Option.
      Returns:
      Option.some(value)
    • toTry

      public Try<T> toTry()
      Evaluates this Lazy inside a Try, capturing any exception thrown by the supplier as a Failure.

      The result is memoized: the supplier is called at most once regardless of how many times this method is invoked.

      Returns:
      Success(value) if the supplier completes normally, or Failure(exception) if it throws
    • fromFuture

      public static <T> Lazy<T> fromFuture(CompletableFuture<? extends T> future)
      Creates a Lazy that defers the blocking wait for future until the first call to get().

      The future's result is obtained via Try.fromFuture(CompletableFuture), which unwraps CompletionException transparently. If the future completed exceptionally, get() rethrows the original RuntimeException or Error as-is, and wraps checked exceptions in a new RuntimeException.

      Type Parameters:
      T - the type of the future's value
      Parameters:
      future - the CompletableFuture to wrap; must not be null
      Returns:
      a new, unevaluated Lazy<T>
      Throws:
      NullPointerException - if future is null
    • toFuture

      public CompletableFuture<T> toFuture()
      Converts this Lazy into a CompletableFuture.

      If the value has already been evaluated (i.e., isEvaluated() is true), returns an already-completed future with the cached value — no thread pool dispatch occurs. Otherwise, evaluates the supplier asynchronously via CompletableFuture.supplyAsync(Supplier).

      Returns:
      a CompletableFuture<T> that completes with this lazy's value
    • toResult

      public Result<T, Throwable> toResult()
      Evaluates this Lazy inside a Result, capturing any exception thrown by the supplier as Err(Throwable).
      Returns:
      Ok(value) if the supplier completes normally, or Err(exception) if it throws
    • toResult

      public <E> Result<T,E> toResult(Function<? super Throwable, ? extends E> errorMapper)
      Evaluates this Lazy inside a Result, converting any exception thrown by the supplier into a typed error using errorMapper.
      Type Parameters:
      E - the error type
      Parameters:
      errorMapper - a function that converts the thrown exception to the error value; must not be null and must not return null
      Returns:
      Ok(value) if the supplier completes normally, or Err(errorMapper.apply(exception)) if it throws
      Throws:
      NullPointerException - if errorMapper is null or returns null
    • toString

      public String toString()
      Returns a string representation of this Lazy.
      Overrides:
      toString in class Object
      Returns:
      "Lazy[?]" if not yet evaluated, "Lazy[value]" if evaluated successfully, or "Lazy[!]" if evaluation failed