src/share/classes/java/util/Map.java

Print this page
rev 8834 : 8029055: Map.merge implementations should refuse null value param
Reviewed-by: duke


1093         V newValue = remappingFunction.apply(key, oldValue);
1094         if (newValue == null) {
1095             // delete mapping
1096             if (oldValue != null || containsKey(key)) {
1097                 // something to remove
1098                 remove(key);
1099                 return null;
1100             } else {
1101                 // nothing to do. Leave things as they were.
1102                 return null;
1103             }
1104         } else {
1105             // add or replace old mapping
1106             put(key, newValue);
1107             return newValue;
1108         }
1109     }
1110 
1111     /**
1112      * If the specified key is not already associated with a value or is
1113      * associated with null, associates it with the given value.
1114      * Otherwise, replaces the value with the results of the given
1115      * remapping function, or removes if the result is {@code null}. This
1116      * method may be of use when combining multiple mapped values for a key.
1117      * For example, to either create or append a {@code String msg} to a
1118      * value mapping:
1119      *
1120      * <pre> {@code
1121      * map.merge(key, msg, String::concat)
1122      * }</pre>
1123      *
1124      * <p>If the function returns {@code null}, the mapping is removed (or
1125      * remains absent if initially absent).  If the function itself throws an
1126      * (unchecked) exception, the exception is rethrown, and the current mapping
1127      * is left unchanged.
1128      *
1129      * @implSpec
1130      * The default implementation is equivalent to performing the
1131      * following steps for this {@code map}, then returning the
1132      * current value or {@code null} if absent:
1133      *
1134      * <pre> {@code
1135      * V oldValue = map.get(key);
1136      * V newValue = (oldValue == null) ? value :
1137      *              remappingFunction.apply(oldValue, value);
1138      * if (newValue == null)
1139      *     map.remove(key);
1140      * else if (oldValue == null)
1141      *     map.remove(key);
1142      * else
1143      *     map.put(key, newValue);
1144      * }</pre>
1145      *
1146      * <p>The default implementation makes no guarantees about synchronization
1147      * or atomicity properties of this method. Any implementation providing
1148      * atomicity guarantees must override this method and document its
1149      * concurrency properties. In particular, all implementations of
1150      * subinterface {@link java.util.concurrent.ConcurrentMap} must document
1151      * whether the function is applied once atomically only if the value is not
1152      * present.
1153      *
1154      * @param key key with which the specified value is to be associated
1155      * @param value the value to use if absent


1156      * @param remappingFunction the function to recompute a value if present
1157      * @return the new value associated with the specified key, or null if none

1158      * @throws UnsupportedOperationException if the {@code put} operation
1159      *         is not supported by this map
1160      *         (<a href="Collection.html#optional-restrictions">optional</a>)
1161      * @throws ClassCastException if the class of the specified key or value
1162      *         prevents it from being stored in this map
1163      *         (<a href="Collection.html#optional-restrictions">optional</a>)
1164      * @throws NullPointerException if the specified key is null and
1165      *         this map does not support null keys, or the remappingFunction
1166      *         is null
1167      * @since 1.8
1168      */
1169     default V merge(K key, V value,
1170             BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
1171         Objects.requireNonNull(remappingFunction);

1172         V oldValue = get(key);
1173         if (oldValue != null) {
1174             V newValue = remappingFunction.apply(oldValue, value);
1175             if (newValue != null) {
1176                 put(key, newValue);
1177                 return newValue;
1178             } else {
1179                 remove(key);
1180                 return null;
1181             }
1182         } else {
1183             if (value == null) {
1184                 remove(key);
1185                 return null;
1186             } else {
1187                 put(key, value);
1188                 return value;
1189             }
1190         }

1191     }
1192 }


1093         V newValue = remappingFunction.apply(key, oldValue);
1094         if (newValue == null) {
1095             // delete mapping
1096             if (oldValue != null || containsKey(key)) {
1097                 // something to remove
1098                 remove(key);
1099                 return null;
1100             } else {
1101                 // nothing to do. Leave things as they were.
1102                 return null;
1103             }
1104         } else {
1105             // add or replace old mapping
1106             put(key, newValue);
1107             return newValue;
1108         }
1109     }
1110 
1111     /**
1112      * If the specified key is not already associated with a value or is
1113      * associated with null, associates it with the given non-null value.
1114      * Otherwise, replaces the associated value with the results of the given
1115      * remapping function, or removes if the result is {@code null}. This
1116      * method may be of use when combining multiple mapped values for a key.
1117      * For example, to either create or append a {@code String msg} to a
1118      * value mapping:
1119      *
1120      * <pre> {@code
1121      * map.merge(key, msg, String::concat)
1122      * }</pre>
1123      *
1124      * <p>If the function returns {@code null} the mapping is removed.  If the
1125      * function itself throws an (unchecked) exception, the exception is
1126      * rethrown, and the current mapping is left unchanged.

1127      *
1128      * @implSpec
1129      * The default implementation is equivalent to performing the following
1130      * steps for this {@code map}, then returning the current value or
1131      * {@code null} if absent:
1132      *
1133      * <pre> {@code
1134      * V oldValue = map.get(key);
1135      * V newValue = (oldValue == null) ? value :
1136      *              remappingFunction.apply(oldValue, value);
1137      * if (newValue == null)
1138      *     map.remove(key);


1139      * else
1140      *     map.put(key, newValue);
1141      * }</pre>
1142      *
1143      * <p>The default implementation makes no guarantees about synchronization
1144      * or atomicity properties of this method. Any implementation providing
1145      * atomicity guarantees must override this method and document its
1146      * concurrency properties. In particular, all implementations of
1147      * subinterface {@link java.util.concurrent.ConcurrentMap} must document
1148      * whether the function is applied once atomically only if the value is not
1149      * present.
1150      *
1151      * @param key key with which the resulting value is to be associated
1152      * @param value the non-null value to be merged with the existing value
1153      *        associated with the key or, if no existing value or a null value
1154      *        is associated with the key, to be associated with the key
1155      * @param remappingFunction the function to recompute a value if present
1156      * @return the new value associated with the specified key, or null if no
1157      *         value is associated with the key
1158      * @throws UnsupportedOperationException if the {@code put} operation
1159      *         is not supported by this map
1160      *         (<a href="Collection.html#optional-restrictions">optional</a>)
1161      * @throws ClassCastException if the class of the specified key or value
1162      *         prevents it from being stored in this map
1163      *         (<a href="Collection.html#optional-restrictions">optional</a>)
1164      * @throws NullPointerException if the specified key or value is null and
1165      *         this map does not support null keys or values, or the
1166      *         remappingFunction is null
1167      * @since 1.8
1168      */
1169     default V merge(K key, V value,
1170             BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
1171         Objects.requireNonNull(remappingFunction);
1172         Objects.requireNonNull(value);
1173         V oldValue = get(key);
1174         V newValue = (oldValue == null) ? value :
1175                    remappingFunction.apply(oldValue, value);
1176         if(newValue == null) {








1177             remove(key);

1178         } else {
1179             put(key, newValue);


1180         }
1181         return newValue;
1182     }
1183 }