src/share/classes/java/util/Map.java
Print this page
rev 8193 : [mq]: JDK-8024688.2
@@ -575,10 +575,11 @@
* this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key is null and this map
* does not permit null keys
* (<a href="Collection.html#optional-restrictions">optional</a>)
+ * @since 1.8
*/
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
@@ -786,11 +787,13 @@
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
- remove(key);
+ if(curValue != remove(key)) {
+ throw new ConcurrentModificationException("value unexpectedly changed");
+ }
return true;
}
/**
* Replaces the entry for the specified key only if currently
@@ -838,13 +841,15 @@
Object curValue = get(key);
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
- put(key, newValue);
+ if(curValue == put(key, newValue)) {
return true;
}
+ throw new ConcurrentModificationException("value unexpectedly changed");
+ }
/**
* Replaces the entry for the specified key only if it is
* currently mapped to some value.
*
@@ -881,11 +886,19 @@
* @throws IllegalArgumentException if some property of the specified key
* or value prevents it from being stored in this map
* @since 1.8
*/
default V replace(K key, V value) {
- return containsKey(key) ? put(key, value) : null;
+ V curValue;
+ if(((curValue = get(key)) != null) || containsKey(key)) {
+ if(curValue == put(key, value)) {
+ return curValue;
+ }
+ } else {
+ return curValue;
+ }
+ throw new ConcurrentModificationException("value unexpectedly changed");
}
/**
* If the specified key is not already associated with a value (or
* is mapped to {@code null}), attempts to compute its value using
@@ -906,12 +919,11 @@
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties. In particular, all implementations of
* subinterface {@link java.util.concurrent.ConcurrentMap} must document
* whether the function is applied once atomically only if the value is not
- * present. Any class that permits null values must document
- * whether and how this method distinguishes absence from null mappings.
+ * present.
*
* @implSpec
* The default implementation is equivalent to the following
* steps for this {@code map}, then returning the current value or
* {@code null} if now absent:
@@ -940,14 +952,21 @@
* @since 1.8
*/
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
- V v, newValue;
- return ((v = get(key)) == null &&
- (newValue = mappingFunction.apply(key)) != null &&
- (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
+ V v;
+ if ((v = get(key)) == null) {
+ V newValue;
+ if ((newValue = mappingFunction.apply(key)) != null) {
+ if (null == putIfAbsent(key, newValue))
+ return newValue;
+ throw new ConcurrentModificationException("expected value changed");
+ }
+ }
+
+ return v;
}
/**
* If the value for the specified key is present and non-null, attempts to
* compute a new mapping given the key and its current mapped value.
@@ -979,13 +998,10 @@
* else
* map.remove(key, oldValue);
* }
* }</pre>
*
- * In concurrent contexts, the default implementation may retry
- * these steps when multiple threads attempt updates.
- *
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key is null and
* this map does not support null keys, or the
@@ -1000,19 +1016,21 @@
*/
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
- while ((oldValue = get(key)) != null) {
+ if((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null) {
if (replace(key, oldValue, newValue))
return newValue;
} else if (remove(key, oldValue))
return null;
+ } else {
+ return null;
}
- return oldValue;
+ throw new ConcurrentModificationException("unexpected value change");
}
/**
* Attempts to compute a mapping for the specified key and its
* current mapped value (or {@code null} if there is no current
@@ -1056,13 +1074,10 @@
* else
* return null;
* }
* }</pre>
*
- * In concurrent contexts, the default implementation may retry
- * these steps when multiple threads attempt updates.
- *
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key is null and
* this map does not support null keys, or the
@@ -1077,23 +1092,20 @@
*/
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
- for (;;) {
+
V newValue = remappingFunction.apply(key, oldValue);
if (newValue == null) {
// delete mapping
if(oldValue != null || containsKey(key)) {
// something to remove
if (remove(key, oldValue)) {
// removed the old value as expected
return null;
}
-
- // some other value replaced old value. try again.
- oldValue = get(key);
} else {
// nothing to do. Leave things as they were.
return null;
}
} else {
@@ -1102,24 +1114,19 @@
// replace
if (replace(key, oldValue, newValue)) {
// replaced as expected.
return newValue;
}
-
- // some other value replaced old value. try again.
- oldValue = get(key);
} else {
// add (replace if oldValue was null)
- if ((oldValue = putIfAbsent(key, newValue)) == null) {
+ if (putIfAbsent(key, newValue) == null) {
// replaced
return newValue;
}
-
- // some other value replaced old value. try again.
- }
}
}
+ throw new ConcurrentModificationException("expected value change");
}
/**
* If the specified key is not already associated with a value or is
* associated with null, associates it with the given value.
@@ -1142,12 +1149,11 @@
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties. In particular, all implementations of
* subinterface {@link java.util.concurrent.ConcurrentMap} must document
* whether the function is applied once atomically only if the value is not
- * present. Any class that permits null values must document
- * whether and how this method distinguishes absence from null mappings.
+ * present.
*
* @implSpec
* The default implementation is equivalent to performing the
* following steps for this {@code map}, then returning the
* current value or {@code null} if absent:
@@ -1162,13 +1168,10 @@
* map.putIfAbsent(key, newValue);
* else
* map.replace(key, oldValue, newValue);
* }</pre>
*
- * In concurrent contexts, the default implementation may retry
- * these steps when multiple threads attempt updates.
- *
* @param key key with which the specified value is to be associated
* @param value the value to use if absent
* @param remappingFunction the function to recompute a value if present
* @return the new value associated with the specified key, or null if none
* @throws UnsupportedOperationException if the {@code put} operation
@@ -1184,27 +1187,27 @@
*/
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
- for (;;) {
if (oldValue != null) {
V newValue = remappingFunction.apply(oldValue, value);
if (newValue != null) {
if (replace(key, oldValue, newValue))
return newValue;
} else if (remove(key, oldValue)) {
return null;
}
- oldValue = get(key);
} else {
if (value == null) {
+ if(remove(key) == null) {
return null;
}
-
- if ((oldValue = putIfAbsent(key, value)) == null) {
+ } else {
+ if (putIfAbsent(key, value) == null) {
return value;
}
}
}
+ throw new ConcurrentModificationException("unexpected value change");
}
}