ConcurrentHashMap/ConcurrentMap/Map.compute
Brian Goetz
brian.goetz at oracle.com
Fri Dec 14 08:46:18 PST 2012
No complaint from me. The alternative seems worse; it says that because
of the existence of null-supporting maps, no one can have these nice new
features.
But, I am not quite following your argument. Why does it fail if you
replace "map.get(key) == null" with "!map.containsKey(key)"? For
non-null-accepting maps they are equivalent.
On 12/14/2012 9:52 AM, Doug Lea wrote:
>
> Back to this after several diversions...
>
> On 12/07/12 11:16, Doug Lea wrote:
>>> Basic idea: defaults for function-accepting Map methods are solely
>>> in terms of the 4 CM methods, which are in turn non-atomic for
>>> non-CM....
>>
>
> Unfortunately the null-value ambiguity hits yet again when
> moving from writing specs to writing default implementations.
> (Have I mentioned lately how terrible it is to allow nulls? :-)
>
> The defaults for function-accepting methods must rely not
> only on these 4 CHM methods, but also on get and/or containsKey.
> For null-accepting maps, you need the pair of them
> to default-implement (non-atomically) but for others,
> you must not use the pair of them (just get) to propagate
> the property that if putIfAbsent is thread-safe then so is
> computeIfAbsent.
>
> The only way out I see is to even further sacrifice
> sensibility for null-accepting maps, by saying that the
> methods are allowed to treat absence and mapping to null
> identically and that the default implementation does so.
> Here's computeIfAbsent. Any complaints?
>
> /**
> * If the specified key is not already associated with a value (or
> * is mapped to {@code null)), attempts to compute its value using
> * the given mapping function and enters it into the map unless
> * {@code null}. The default implementation is equivalent to the
> * following, then returning the current value or {@code null} if
> * absent:
> *
> * <pre> {@code
> * if (map.get(key) == null) {
> * V newValue = mappingFunction.apply(key);
> * if (newValue != null)
> * map.putIfAbsent(key, newValue);
> * }}</pre>
> *
> * If the function returns {@code null} no mapping is recorded. If
> * the function itself throws an (unchecked) exception, the
> * exception is rethrown to its caller, and no mapping is
> * recorded. The most common usage is to construct a new object
> * serving as an initial mapped value or memoized result, as in:
> *
> * <pre> {@code
> * map.computeIfAbsent(key, k -> new Value(f(k)));} </pre>
> *
> * <p>The default implementation makes no guarantees about
> * synchronization or atomicity properties of this method or the
> * application of the mapping function. Any class overriding this
> * method must specify 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.
> *
> * @param key key with which the specified value is to be associated
> * @param mappingFunction the function to compute a value
> * @return the current (existing or computed) value associated with
> * the specified key, or null if the computed value is null
> * @throws NullPointerException if the specified key is null and
> * this map does not support null keys, or the
> * mappingFunction is null
> * @throws UnsupportedOperationException if the <tt>put</tt> operation
> * is not supported by this map
> * @throws ClassCastException if the class of the specified key or
> value
> * prevents it from being stored in this map
> * @throws RuntimeException or Error if the mappingFunction does so,
> * in which case the mapping is left unestablished
> */
> default V computeIfAbsent(K key, Function<? super K, ? extends V>
> mappingFunction) {
> V v, newValue;
> return ((v = get(key)) == null &&
> (newValue = mappingFunction.apply(key)) != null &&
> (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
> }
>
More information about the lambda-libs-spec-observers
mailing list