On Dec 11, 2013, at 1:27 AM, Mike Duigou <[email protected]> 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.

Reply via email to