src/share/classes/java/util/Map.java
Print this page
rev 8193 : [mq]: JDK-8024688.2
*** 575,584 ****
--- 575,585 ----
* 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,796 ****
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
! remove(key);
return true;
}
/**
* Replaces the entry for the specified key only if currently
--- 787,799 ----
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
! if(curValue != remove(key)) {
! throw new ConcurrentModificationException("value unexpectedly changed");
! }
return true;
}
/**
* Replaces the entry for the specified key only if currently
*** 838,850 ****
Object curValue = get(key);
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
! put(key, newValue);
return true;
}
/**
* Replaces the entry for the specified key only if it is
* currently mapped to some value.
*
--- 841,855 ----
Object curValue = get(key);
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
! 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,891 ****
* @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;
}
/**
* If the specified key is not already associated with a value (or
* is mapped to {@code null}), attempts to compute its value using
--- 886,904 ----
* @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) {
! 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,917 ****
* 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.
*
* @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:
--- 919,929 ----
* 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.
*
* @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,953 ****
* @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;
}
/**
* 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.
--- 952,972 ----
* @since 1.8
*/
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
! 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,991 ****
* 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
--- 998,1007 ----
*** 1000,1018 ****
*/
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
! while ((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;
}
! return oldValue;
}
/**
* Attempts to compute a mapping for the specified key and its
* current mapped value (or {@code null} if there is no current
--- 1016,1036 ----
*/
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
! 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;
}
! 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,1068 ****
* 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
--- 1074,1083 ----
*** 1077,1099 ****
*/
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 {
--- 1092,1111 ----
*/
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
!
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;
}
} else {
// nothing to do. Leave things as they were.
return null;
}
} else {
*** 1102,1125 ****
// 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) {
// replaced
return newValue;
}
-
- // some other value replaced old value. try again.
- }
}
}
}
/**
* If the specified key is not already associated with a value or is
* associated with null, associates it with the given value.
--- 1114,1132 ----
// replace
if (replace(key, oldValue, newValue)) {
// replaced as expected.
return newValue;
}
} else {
// add (replace if oldValue was null)
! if (putIfAbsent(key, newValue) == null) {
// replaced
return newValue;
}
}
}
+ 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,1153 ****
* 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.
*
* @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:
--- 1149,1159 ----
* 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.
*
* @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,1174 ****
* 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
--- 1168,1177 ----
*** 1184,1210 ****
*/
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) {
return null;
}
!
! if ((oldValue = putIfAbsent(key, value)) == null) {
return value;
}
}
}
}
}
--- 1187,1213 ----
*/
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
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;
}
} else {
if (value == null) {
+ if(remove(key) == null) {
return null;
}
! } else {
! if (putIfAbsent(key, value) == null) {
return value;
}
}
}
+ throw new ConcurrentModificationException("unexpected value change");
}
}