Interface StableValue<V>

Type Parameters:
V - value type

public sealed interface StableValue<V>
An atomic, thread-safe, stable value holder for which the value can be set at most once.

Stable values are eligible for constant folding and other optimizations by the JVM.

A stable value is said to be monotonic because the state of a stable value can only go from unset to set and consequently, a value can only be set at most once.

To create a new fresh (unset) StableValue, use the of() factory.

To create collections of wrapped stable elements, that, in turn, are also eligible for constant folding optimizations, the following factories can be used:

Except for a StableValue's value itself, all method parameters must be non-null and all collections provided must only contain non-null elements or a NullPointerException will be thrown.

Since:
23
  • Method Summary

    Modifier and Type
    Method
    Description
    computeIfUnset(Supplier<? extends V> supplier)
    If no value is set, attempts to compute and set a new (nullable) value using the provided supplier, returning the (pre-existing or newly set) value.
    static <V> V
    computeIfUnset(List<StableValue<V>> list, int index, IntFunction<? extends V> mapper)
    If no value is set for the StableValue at the provided index, attempts to compute and set it as per computeIfUnset(Supplier) by applying the provided mapper.
    static <K, V> V
    computeIfUnset(Map<K,StableValue<V>> map, K key, Function<? super K,? extends V> mapper)
    If no value is set for the StableValue for the provided key, attempts to compute and set it as per computeIfUnset(Supplier) by applying the provided mapper.
    boolean
    Returns true if a value is set, otherwise false.
    static <V> StableValue<V>
    of()
    Returns a fresh stable value with an unset value.
    static <V> StableValue<V>
    ofBackground(Supplier<? extends V> supplier)
    Returns a fresh stable value with an unset value where the returned stable's value is computed in a separate fresh background thread using the provided supplier.
    static <V> List<StableValue<V>>
    ofList(int size)
    Returns an unmodifiable, shallowly immutable, thread-safe, stable, List containing size StableValue elements.
    static <K, V> Map<K,StableValue<V>>
    ofMap(Set<? extends K> keys)
    Returns an unmodifiable, shallowly immutable, thread-safe, value-stable, Map where the keys contains precisely the distinct provided set of keys and where the stable values are, in turn, lazily computed upon being accessed (e.g. via get(key)).
    Returns the set value (nullable) if set, otherwise throws NoSuchElementException.
    setIfUnset(V value)
    If no value is set, sets the stable value to the provided (nullable) value, returning the (pre-existing or newly set) value.
    void
    setOrThrow(V value)
    Sets the stable value to the provided (nullable) value or throws an IllegalStateException if a value is already set.
  • Method Details

    • orThrow

      V orThrow()
      Returns the set value (nullable) if set, otherwise throws NoSuchElementException.
      Returns:
      the set value (nullable) if set, otherwise throws NoSuchElementException
      Throws:
      NoSuchElementException - if no value is set
    • isSet

      boolean isSet()
      Returns true if a value is set, otherwise false.
      Returns:
      true if a value is set, otherwise false
    • setOrThrow

      void setOrThrow(V value)
      Sets the stable value to the provided (nullable) value or throws an IllegalStateException if a value is already set.
      Parameters:
      value - to set (nullable)
      Throws:
      IllegalStateException - if a value is already set
    • setIfUnset

      V setIfUnset(V value)
      If no value is set, sets the stable value to the provided (nullable) value, returning the (pre-existing or newly set) value.

      If several threads invoke this method simultaneously, only one thread will succeed in setting a value and that (witness) value will be returned to all threads.

      Parameters:
      value - to set (nullable)
      Returns:
      the bound value
    • computeIfUnset

      V computeIfUnset(Supplier<? extends V> supplier)
      If no value is set, attempts to compute and set a new (nullable) value using the provided supplier, returning the (pre-existing or newly set) value.

      If the supplier throws an (unchecked) exception, the exception is rethrown, and no value is set. The most common usage is to construct a new object serving as a lazily computed value or memoized result, as in:

       
       Value witness = stable.computeIfUnset(Value::new);
       
      Implementation Requirements:
      The implementation logic is equivalent to the following steps for this stable:
       
       if (stable.isBound()) {
           return stable.get();
       } else {
           V newValue = supplier.get();
           stable.setOrThrow(newValue);
           return newValue;
       }
       
      Except it is atomic, thread-safe and will only return the same witness value regardless if invoked by several threads. Also, the provided supplier will only be invoked once even if invoked from several threads.
      Parameters:
      supplier - to be used for computing a value
      Returns:
      the current (pre-existing or computed) value
    • of

      static <V> StableValue<V> of()
      Returns a fresh stable value with an unset value.
      Type Parameters:
      V - the value type to set
      Returns:
      a fresh stable value with an unset value
    • ofBackground

      static <V> StableValue<V> ofBackground(Supplier<? extends V> supplier)
      Returns a fresh stable value with an unset value where the returned stable's value is computed in a separate fresh background thread using the provided supplier.

      If the supplier throws an (unchecked) exception, the exception is ignored, and no value is set.

      Type Parameters:
      V - the value type to set
      Parameters:
      supplier - to be used for computing a value
      Returns:
      a fresh stable value with an unset value where the returned stable's value is computed in a separate fresh background thread using the provided supplier
      See Also:
    • ofList

      static <V> List<StableValue<V>> ofList(int size)
      Returns an unmodifiable, shallowly immutable, thread-safe, stable, List containing size StableValue elements.

      If non-empty, neither the returned list nor its elements are Serializable.

      The returned list and its elements are eligible for constant folding and other optimizations by the JVM and is equivalent to:

       List<StableValue<V>> list = Stream.generate(StableValue::<V>of)
               .limit(size)
               .toList();
      
      Except it requires less storage, does not return stable value instances with the same identity, and is likely to exhibit better performance.

      This static factory methods return list instances (and with all their elements) that are value-based, immutable and thread-safe. Programmers should not use list and element instances for synchronization, or unpredictable behavior may occur. For example, in a future release, synchronization may fail. Consequently, query methods List.contains(Object), List.containsAll(Collection) (if non-empty), List.indexOf(Object), List.lastIndexOf(Object), and methods that relies on these method or similar methods will always indicate no match.

      Type Parameters:
      V - the generic type of the stable value elements in the returned List
      Parameters:
      size - the number of elements in the list
      Returns:
      an unmodifiable, shallowly immutable, thread-safe, stable, List containing size StableValue elements
      Throws:
      IllegalArgumentException - if the provided size is negative
      Since:
      23
    • ofMap

      static <K, V> Map<K,StableValue<V>> ofMap(Set<? extends K> keys)
      Returns an unmodifiable, shallowly immutable, thread-safe, value-stable, Map where the keys contains precisely the distinct provided set of keys and where the stable values are, in turn, lazily computed upon being accessed (e.g. via get(key)).

      If non-empty, neither the returned map nor its values are Serializable.

      The returned map and its values are eligible for constant folding and other optimizations by the JVM and is equivalent to:

      Map<K, StableValue<V>> map = Map.copyOf(keys.stream()
              .distinct()
              .map(Objects::requireNonNull)
              .collect(Collectors.toMap(Function.identity(), _ -> StableValue.of())));
      
      Except it requires less storage, does not return stable value instances with the same identity, and is likely to exhibit better performance.

      This static factory methods return map instances (and with all their values) that are value-based, immutable and thread-safe. Programmers should not use map and value instances for synchronization, or unpredictable behavior may occur. For example, in a future release, synchronization may fail. Consequently, the query methods Map.containsValue(Object) and methods that relies on this and similar method will always indicate no match.

      As an emerging property, providing an EnumSet as keys will make the returned Map eligible for certain additional optimizations.

      Type Parameters:
      K - the type of keys maintained by the returned map
      V - the type of mapped StableValue values
      Parameters:
      keys - the keys in the map
      Returns:
      an unmodifiable, shallowly immutable, thread-safe, value-stable, Map where the keys contains precisely the distinct provided set of keys and where the stable values are, in turn, lazily computed upon being accessed (e.g. via get(key))
    • computeIfUnset

      static <V> V computeIfUnset(List<StableValue<V>> list, int index, IntFunction<? extends V> mapper)
      If no value is set for the StableValue at the provided index, attempts to compute and set it as per computeIfUnset(Supplier) by applying the provided mapper.

      This is equivalent to:

       StableValue<V> stable = list.get(index);
       if (stable.isSet()) {
           return stable.orThrow();
       }
       Supplier<V> supplier = () -> mapper.apply(index);
       return stable.computeIfUnset(supplier);
      
      Except it might be more resource efficient and performant.
      Type Parameters:
      V - the StableValue type to set
      Parameters:
      list - from which to get a StableValue
      index - for the StableValue
      mapper - to apply if the StableValue at the provided index is not set
      Returns:
      the current (pre-existing or computed) value at the provided index
      Throws:
      IndexOutOfBoundsException - if the provided index is less than zero or index >= list.size()
    • computeIfUnset

      static <K, V> V computeIfUnset(Map<K,StableValue<V>> map, K key, Function<? super K,? extends V> mapper)
      If no value is set for the StableValue for the provided key, attempts to compute and set it as per computeIfUnset(Supplier) by applying the provided mapper.

      This is equivalent to:

       StableValue<V> stable = map.get(key);
       if (stable == null) {
            throw new NoSuchElementException("Unknown key: "+key);
       }
       if (stable.isSet()) {
           return stable.orThrow();
       }
       Supplier<V> supplier = () -> mapper.apply(key);
       return stable.computeIfUnset(supplier);
      
      Except it might be more resource efficient and performant.
      Type Parameters:
      K - the type of keys maintained by this map
      V - the StableValue value type to set
      Parameters:
      map - from which to get a Stab;eValue
      key - associated with a StableValue
      mapper - to apply if the StableValue associated with the provided key is not set
      Returns:
      the current (pre-existing or computed) value for the provided key
      Throws:
      NoSuchElementException - if the provided map does not contain the provided key