提交 63c90b76 编写于 作者: M mduigou

8029055: Map.merge implementations should refuse null value param

Reviewed-by: briangoetz, dl
上级 9805086f
...@@ -1212,6 +1212,8 @@ public class HashMap<K,V> extends AbstractMap<K,V> ...@@ -1212,6 +1212,8 @@ public class HashMap<K,V> extends AbstractMap<K,V>
@Override @Override
public V merge(K key, V value, public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) { BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (value == null)
throw new NullPointerException();
if (remappingFunction == null) if (remappingFunction == null)
throw new NullPointerException(); throw new NullPointerException();
int hash = hash(key); int hash = hash(key);
......
...@@ -600,7 +600,7 @@ public interface Map<K,V> { ...@@ -600,7 +600,7 @@ public interface Map<K,V> {
* @implSpec * @implSpec
* The default implementation is equivalent to, for this {@code map}: * The default implementation is equivalent to, for this {@code map}:
* <pre> {@code * <pre> {@code
* for ((Map.Entry<K, V> entry : map.entrySet()) * for (Map.Entry<K, V> entry : map.entrySet())
* action.accept(entry.getKey(), entry.getValue()); * action.accept(entry.getKey(), entry.getValue());
* }</pre> * }</pre>
* *
...@@ -640,7 +640,7 @@ public interface Map<K,V> { ...@@ -640,7 +640,7 @@ public interface Map<K,V> {
* @implSpec * @implSpec
* <p>The default implementation is equivalent to, for this {@code map}: * <p>The default implementation is equivalent to, for this {@code map}:
* <pre> {@code * <pre> {@code
* for ((Map.Entry<K, V> entry : map.entrySet()) * for (Map.Entry<K, V> entry : map.entrySet())
* entry.setValue(function.apply(entry.getKey(), entry.getValue())); * entry.setValue(function.apply(entry.getKey(), entry.getValue()));
* }</pre> * }</pre>
* *
...@@ -1110,8 +1110,8 @@ public interface Map<K,V> { ...@@ -1110,8 +1110,8 @@ public interface Map<K,V> {
/** /**
* If the specified key is not already associated with a value or is * If the specified key is not already associated with a value or is
* associated with null, associates it with the given value. * associated with null, associates it with the given non-null value.
* Otherwise, replaces the value with the results of the given * Otherwise, replaces the associated value with the results of the given
* remapping function, or removes if the result is {@code null}. This * remapping function, or removes if the result is {@code null}. This
* method may be of use when combining multiple mapped values for a key. * method may be of use when combining multiple mapped values for a key.
* For example, to either create or append a {@code String msg} to a * For example, to either create or append a {@code String msg} to a
...@@ -1121,15 +1121,14 @@ public interface Map<K,V> { ...@@ -1121,15 +1121,14 @@ public interface Map<K,V> {
* map.merge(key, msg, String::concat) * map.merge(key, msg, String::concat)
* }</pre> * }</pre>
* *
* <p>If the function returns {@code null}, the mapping is removed (or * <p>If the function returns {@code null} the mapping is removed. If the
* remains absent if initially absent). If the function itself throws an * function itself throws an (unchecked) exception, the exception is
* (unchecked) exception, the exception is rethrown, and the current mapping * rethrown, and the current mapping is left unchanged.
* is left unchanged.
* *
* @implSpec * @implSpec
* The default implementation is equivalent to performing the * The default implementation is equivalent to performing the following
* following steps for this {@code map}, then returning the * steps for this {@code map}, then returning the current value or
* current value or {@code null} if absent: * {@code null} if absent:
* *
* <pre> {@code * <pre> {@code
* V oldValue = map.get(key); * V oldValue = map.get(key);
...@@ -1137,8 +1136,6 @@ public interface Map<K,V> { ...@@ -1137,8 +1136,6 @@ public interface Map<K,V> {
* remappingFunction.apply(oldValue, value); * remappingFunction.apply(oldValue, value);
* if (newValue == null) * if (newValue == null)
* map.remove(key); * map.remove(key);
* else if (oldValue == null)
* map.remove(key);
* else * else
* map.put(key, newValue); * map.put(key, newValue);
* }</pre> * }</pre>
...@@ -1151,42 +1148,36 @@ public interface Map<K,V> { ...@@ -1151,42 +1148,36 @@ public interface Map<K,V> {
* whether the function is applied once atomically only if the value is not * whether the function is applied once atomically only if the value is not
* present. * present.
* *
* @param key key with which the specified value is to be associated * @param key key with which the resulting value is to be associated
* @param value the value to use if absent * @param value the non-null value to be merged with the existing value
* associated with the key or, if no existing value or a null value
* is associated with the key, to be associated with the key
* @param remappingFunction the function to recompute a value if present * @param remappingFunction the function to recompute a value if present
* @return the new value associated with the specified key, or null if none * @return the new value associated with the specified key, or null if no
* value is associated with the key
* @throws UnsupportedOperationException if the {@code put} operation * @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map * is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>) * (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of the specified key or value * @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map * prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>) * (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key is null and * @throws NullPointerException if the specified key is null and this map
* this map does not support null keys, or the remappingFunction * does not support null keys or the value or remappingFunction is
* is null * null
* @since 1.8 * @since 1.8
*/ */
default V merge(K key, V value, default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) { BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction); Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key); V oldValue = get(key);
if (oldValue != null) { V newValue = (oldValue == null) ? value :
V newValue = remappingFunction.apply(oldValue, value); remappingFunction.apply(oldValue, value);
if (newValue != null) { if(newValue == null) {
put(key, newValue); remove(key);
return newValue;
} else {
remove(key);
return null;
}
} else { } else {
if (value == null) { put(key, newValue);
remove(key);
return null;
} else {
put(key, value);
return value;
}
} }
return newValue;
} }
} }
...@@ -463,9 +463,9 @@ public interface ConcurrentMap<K, V> extends Map<K, V> { ...@@ -463,9 +463,9 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* {@inheritDoc} * {@inheritDoc}
* *
* @implSpec * @implSpec
* The default implementation is equivalent to performing the * The default implementation is equivalent to performing the following
* following steps for this {@code map}, then returning the * steps for this {@code map}, then returning the current value or
* current value or {@code null} if absent: * {@code null} if absent:
* *
* <pre> {@code * <pre> {@code
* V oldValue = map.get(key); * V oldValue = map.get(key);
...@@ -473,8 +473,6 @@ public interface ConcurrentMap<K, V> extends Map<K, V> { ...@@ -473,8 +473,6 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* remappingFunction.apply(oldValue, value); * remappingFunction.apply(oldValue, value);
* if (newValue == null) * if (newValue == null)
* map.remove(key); * map.remove(key);
* else if (oldValue == null)
* map.remove(key);
* else * else
* map.put(key, newValue); * map.put(key, newValue);
* }</pre> * }</pre>
......
...@@ -741,7 +741,6 @@ public class Defaults { ...@@ -741,7 +741,6 @@ public class Defaults {
Collection<Object[]> cases = new ArrayList<>(); Collection<Object[]> cases = new ArrayList<>();
cases.addAll(makeMergeTestCases()); cases.addAll(makeMergeTestCases());
cases.addAll(makeMergeNullValueTestCases());
return cases.iterator(); return cases.iterator();
} }
...@@ -764,32 +763,6 @@ public class Defaults { ...@@ -764,32 +763,6 @@ public class Defaults {
return cases; return cases;
} }
static Collection<Object[]> makeMergeNullValueTestCases() {
Collection<Object[]> cases = new ArrayList<>();
for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NULL, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
}
for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NULL, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
}
for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NULL, Merging.Merger.UNUSED, Merging.Value.ABSENT, Merging.Value.NULL });
}
for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.NULL, Merging.Value.NULL, Merging.Merger.UNUSED, Merging.Value.ABSENT, Merging.Value.NULL });
}
for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.NULL, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
}
return cases;
}
public interface Thrower<T extends Throwable> { public interface Thrower<T extends Throwable> {
public void run() throws T; public void run() throws T;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册