Interface StableValue<V>
- Type Parameters:
V
- value type
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 TypeMethodDescriptioncomputeIfUnset
(Supplier<? extends V> supplier) If no value is set, attempts to compute and set a new (nullable) value using the providedsupplier
, 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 providedindex
, attempts to compute and set it as per computeIfUnset(Supplier) by applying the providedmapper
.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 providedkey
, attempts to compute and set it as per computeIfUnset(Supplier) by applying the providedmapper
.boolean
isSet()
Returnstrue
if a value is set, otherwisefalse
.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 providedsupplier
.static <V> List
<StableValue<V>> ofList
(int size) Returns an unmodifiable, shallowly immutable, thread-safe, stable, List containingsize
StableValue elements.static <K,
V> Map <K, StableValue<V>> orThrow()
Returns the set value (nullable) if set, otherwise throwsNoSuchElementException
.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 throwsNoSuchElementException
.- Returns:
- the set value (nullable) if set, otherwise throws
NoSuchElementException
- Throws:
NoSuchElementException
- if no value is set
-
isSet
boolean isSet()Returnstrue
if a value is set, otherwisefalse
.- Returns:
true
if a value is set, otherwisefalse
-
setOrThrow
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
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
If no value is set, attempts to compute and set a new (nullable) value using the providedsupplier
, 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; }
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
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
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 providedsupplier
.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
Returns an unmodifiable, shallowly immutable, thread-safe, stable, List containingsize
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();
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 returnedList
- 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 providedsize
is negative- Since:
- 23
-
ofMap
Returns an unmodifiable, shallowly immutable, thread-safe, value-stable, Map where the keys contains precisely the distinct provided set ofkeys
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())));
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 mapV
- 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
If no value is set for the StableValue at the providedindex
, attempts to compute and set it as per computeIfUnset(Supplier) by applying the providedmapper
.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);
- Type Parameters:
V
- the StableValue type to set- Parameters:
list
- from which to get a StableValueindex
- for the StableValuemapper
- to apply if the StableValue at the providedindex
is not set- Returns:
- the current (pre-existing or computed) value at the provided
index
- Throws:
IndexOutOfBoundsException
- if the providedindex
is less than zero orindex >= 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 providedkey
, attempts to compute and set it as per computeIfUnset(Supplier) by applying the providedmapper
.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);
- Type Parameters:
K
- the type of keys maintained by this mapV
- the StableValue value type to set- Parameters:
map
- from which to get a Stab;eValuekey
- associated with a StableValuemapper
- to apply if the StableValue associated with the providedkey
is not set- Returns:
- the current (pre-existing or computed) value for the provided
key
- Throws:
NoSuchElementException
- if the providedmap
does not contain the providedkey
-