RFR: 8351565: Implement JEP 502: Stable Values (Preview) [v56]
Viktor Klang
vklang at openjdk.org
Thu Apr 17 11:10:12 UTC 2025
On Thu, 10 Apr 2025 14:19:25 GMT, Per Minborg <pminborg at openjdk.org> wrote:
>> Implement JEP 502.
>>
>> The PR passes tier1-tier3 tests.
>
> Per Minborg has updated the pull request incrementally with one additional commit since the last revision:
>
> Address comments on original vs underlying
Last review pass? :)
src/java.base/share/classes/java/lang/StableValue.java line 204:
> 202: * Set.of(1, 2, 4, 8, 16, 32);
> 203: * private static final UnaryOperator<Integer> UNDERLYING_LOG2 =
> 204: * i -> 31 - Integer.numberOfLeadingZeros(i);
Would boxing be necessary—i.e. what would be needed to use java.util.function.IntUnaryOperator?
src/java.base/share/classes/java/lang/StableValue.java line 318:
> 316: * <p>
> 317: * Another example, which has a more complex dependency graph, is to lazily computing the
> 318: * Fibonacci sequence:
Suggestion:
* Another example, which has a more complex dependency graph, is to compute the
* Fibonacci sequence lazily:
src/java.base/share/classes/java/lang/StableValue.java line 410:
> 408: * parameter, and an {@linkplain #equals(Object) equals(obj)} parameter; all
> 409: * method parameters must be <em>non-null</em> or a {@link NullPointerException}
> 410: * will be thrown.
@minborg @mcimadamore I wonder if it makes more sense to specify that an implementation is free to synchronize on `this`, and as such, as a user, it is should be avoided to synchronize on StableValues.
This leaves the choice open to the implementations whether they want to synchonize on `this` or use some other shceme, while still discouraging users from synchronizing on StableValue instances.
src/java.base/share/classes/java/lang/StableValue.java line 415:
> 413: * a class and is usually neither exposed directly via accessors nor passed as
> 414: * a method parameter.
> 415: * Stable functions and collections make all reasonable efforts to provide
Suggestion:
* Stable functions and collections make reasonable efforts to provide
src/java.base/share/classes/java/lang/StableValue.java line 418:
> 416: * {@link Object#toString()} operations that do not trigger evaluation
> 417: * of the internal stable values when called.
> 418: * Stable collections have {@link Object#equals(Object)} operations that tries
Suggestion:
* Stable collections have {@link Object#equals(Object)} operations that try
src/java.base/share/classes/java/lang/StableValue.java line 422:
> 420: * As objects can be set via stable values but never removed, this can be a source
> 421: * of unintended memory leaks. A stable value's content is
> 422: * {@linkplain java.lang.ref##reachability strongly reachable}. Clients are
I wonder if "Clients" is the best word here. Perhaps "Developers"?
src/java.base/share/classes/java/lang/StableValue.java line 487:
> 485: * <p>
> 486: * If the supplier throws an (unchecked) exception, the exception is rethrown, and no
> 487: * content is set. The most common usage is to construct a new object serving
Suggestion:
* If the supplier throws an (unchecked) exception, the exception is rethrown and no
* content is set. The most common usage is to construct a new object serving
src/java.base/share/classes/java/lang/StableValue.java line 571:
> 569: * thrown by the computing thread.
> 570: * <p>
> 571: * If the provided {@code underlying} supplier throws an exception, it is relayed
Suggestion:
* If the provided {@code underlying} supplier throws an exception, it is rethrown
src/java.base/share/classes/java/lang/StableValue.java line 670:
> 668: * (e.g. via {@linkplain List#get(int) List::get}).
> 669: * <p>
> 670: * The provided {@code mapper} int function is guaranteed to be successfully invoked
Suggestion:
* The provided {@code mapper} function is guaranteed to be successfully invoked
src/java.base/share/classes/java/lang/StableValue.java line 720:
> 718: * <p>
> 719: * If the provided {@code mapper} throws an exception, it is relayed to the initial
> 720: * caller and no value associated with the provided key is recorded.
Suggestion:
* If invoking the provided {@code mapper} function throws an exception, it is rethrown to the initial
* caller and no value associated with the provided key is recorded.
src/java.base/share/classes/java/util/ImmutableCollections.java line 36:
> 34: import java.lang.reflect.Array;
> 35: import java.util.function.BiConsumer;
> 36: import java.util.function.BiFunction;
Make sure to update the copyright years of all the files modified in this PR.
test/jdk/java/lang/StableValue/StableMapTest.java line 140:
> 138: String actual = newMap().toString();
> 139: assertTrue(actual.startsWith("{"));
> 140: for (int key:KEYS) {
Suggestion:
for (int key : KEYS) {
test/jdk/java/lang/StableValue/StableMapTest.java line 317:
> 315: Consumer<Map<Integer, Integer>> consumer) implements Consumer<Map<Integer, Integer>> {
> 316: @java.lang.Override
> 317: public void accept(Map<Integer, Integer> map) { consumer.accept(map); }
Suggestion:
public void accept(Map<Integer, Integer> map) { consumer.accept(map); }
test/jdk/java/lang/StableValue/StableMapTest.java line 324:
> 322: static Stream<Operation> nullAverseOperations() {
> 323: return Stream.of(
> 324: new Operation("forEach", m -> m.forEach(null))
Suggestion:
new Operation("forEach", m -> m.forEach(null))
test/jdk/java/lang/StableValue/StableMapTest.java line 341:
> 339: new Operation("replace2", m -> m.replace(KEY, 1)),
> 340: new Operation("replace3", m -> m.replace(KEY, KEY, 1)),
> 341: new Operation("replaceAll", m -> m.replaceAll((a, _) -> a))
Suggestion:
new Operation("clear", Map::clear),
new Operation("compute", m -> m.compute(KEY, (_, _) -> 1)),
new Operation("computeIfAbsent", m -> m.computeIfAbsent(KEY, _ -> 1)),
new Operation("computeIfPresent", m -> m.computeIfPresent(KEY, (_, _) -> 1)),
new Operation("merge", m -> m.merge(KEY, KEY, (a, _) -> a)),
new Operation("put", m -> m.put(0, 0)),
new Operation("putAll", m -> m.putAll(Map.of())),
new Operation("remove1", m -> m.remove(KEY)),
new Operation("remove2", m -> m.remove(KEY, KEY)),
new Operation("replace2", m -> m.replace(KEY, 1)),
new Operation("replace3", m -> m.replace(KEY, KEY, 1)),
new Operation("replaceAll", m -> m.replaceAll((a, _) -> a))
-------------
PR Review: https://git.openjdk.org/jdk/pull/23972#pullrequestreview-2775117821
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048580493
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048568958
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048697517
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048698149
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048698693
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048700350
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048703097
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048705582
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048707720
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048709836
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048720211
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048722073
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048723018
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048723430
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2048724778
More information about the core-libs-dev
mailing list