RFR: 8029795 : LinkedHashMap.getOrDefault() doesn't update access order. (was Why doesn't new Map methods generate entry accesses on LinkedHashMap?)
Paul Sandoz
paul.sandoz at oracle.com
Wed Dec 11 10:32:19 UTC 2013
On Dec 11, 2013, at 1:27 AM, Mike Duigou <mike.duigou at oracle.com> wrote:
> I have added tests and documentation for the other methods.
>
> http://cr.openjdk.java.net/~mduigou/JDK-8029795/1/webrev/
>
> The documentation for some of the methods is ambiguous about how many access events are generated. For LRU cache is OK but other cases (counting based eviction) may care about the total number of accesses.
+ * invocation completes). Invoking the {@code replace}, {@code merge},
+ * {@code compute} or {@code computeIfPresent} methods results in one or more
+ * accesses of the corresponding entry. The {@code putAll} method generates one
If i look at the code for say replace it generates *at most one access* in terms of affecting last access order, if the entry exists and if the old/new value constraint holds:
@Override
public boolean replace(K key, V oldValue, V newValue) {
Node<K,V> e; V v;
if ((e = getNode(hash(key), key)) != null &&
((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
e.value = newValue;
afterNodeAccess(e);
return true;
}
return false;
}
I have attempted to categorise the access behaviour of each method:
get:
access to entry, if it exists
put:
access to new entry
putIfAbsent
access to entry, if it exists
otherwise access to new entry
replace(K key, V value)
access to entry, if it exists
replace(K key, V oldValue, V newValue)
access to entry, if it exists and it's value is updated
computeIfAbsent:
access to entry, if it exists and it's value is non-null, or
access to entry, if it exists and it's null value is updated to a non-null value [*],
otherwise access to new entry, if created
computeIfPresent
access to entry, if it exists and it's non-null value is updated to a non-null value
compute
access to entry, if it exists and it's value is updated to a non-null value,
otherwise access to new entry, if created
merge
access to entry, if it exists and it's value is updated to a non-null value,
otherwise access to new entry, if created
Patterns, to help group for documentation:
get/put/putIfAbsent/replace(K key, V value): access to entry associated with the key, if entry exists after invocation completes
replace(K key, V oldValue, V newValue): access to entry associated with the key, if returns true
computeIfAbsent/computeIfPresent/compute/merge: access to entry associated with the key, if returns a non-null value.
--
[*] There is some ambiguity with computeIfAbsent. When the entry exists, it's value is null, and the value returned from the mapping function is null then, an access to that entry occurs:
V v = mappingFunction.apply(key);
if (old != null) {
old.value = v;
afterNodeAccess(old);
return v;
}
else if (v == null)
return null;
Is that a bug? I would have expected the returning of null from the mapping function to signal no-action to be taken. Thus computeIfPresent and computeIfAbsent have no side-effects for an existing entry whose value is null when the function returns null (same applies to merge, if the value parameter is null or the remapping function returns null, and to compute, if the remapping function returns null).
So perhaps that code should be:
V v = mappingFunction.apply(key);
if (v == null)
return null;
else if (old != null) {
old.value = v;
afterNodeAccess(old);
return v;
}
Paul.
More information about the core-libs-dev
mailing list