Hi Claes,

On 2020-05-19 15:15, Christoph Dreis wrote:
>> Hi Claes,
>> 
>>> unlike CHM, HashMap and LinkedHashMap have constant-time size/isEmpty
>>>   accessors - could this be used to simplify your patch?
>> 
>> I was wondering about that during implementation, but simply took the path I 
>> already chose for the CHM.

> I think we should try to keep any changes here as simple as possible.

Please find an alternative solution attached that does isEmpty() checks for 
get() and containsKey() calls.

With the provided solution and the combined (empty & non-empty maps) 
benchmarks, I get the following results:

MyBenchmarkNew.test                    avgt   10   4,479 ±  0,061   ns/op
MyBenchmarkOld.test                      avgt   10   4,877 ±  0,054   ns/op

I should note that I see a slightly higher average timing with a filled map 
with the isEmpty() version:

MyBenchmarkNew.test                    avgt   10   5,465 ±  0,354   ns/op
MyBenchmarkOld.test                      avgt   10   5,315 ±  0,187   ns/op

Isolated benchmarks on just an empty map show the following results (for 
completeness reasons):

MyBenchmarkNew.test                      avgt   10   2,785 ±  0,191   ns/op
MyBenchmarkOld.test                        avgt   10   3,785 ±  0,436   ns/op

I can somewhat explain the higher average timing on a filled map with this 
solution:
It actually does "more" work by checking for the size, while the previous 
solution shifted only existing work to a place where it's actually needed.

I would probably go for the first version although it is a bit more complicated 
and has the computeIfPresent caveat, because it doesn't slow down the common 
Map.get() case when the map is actually filled.

Let me know what you think.

Cheers,
Christoph 

diff -r f143729ca00e src/java.base/share/classes/java/util/HashMap.java
--- a/src/java.base/share/classes/java/util/HashMap.java        Wed May 13 
16:18:16 2020 +0200
+++ b/src/java.base/share/classes/java/util/HashMap.java        Tue May 19 
19:36:12 2020 +0200
@@ -555,7 +555,7 @@
      */
     public V get(Object key) {
         Node<K,V> e;
-        return (e = getNode(hash(key), key)) == null ? null : e.value;
+        return isEmpty() || (e = getNode(hash(key), key)) == null ? null : 
e.value;
     }
 
     /**
@@ -594,7 +594,7 @@
      * key.
      */
     public boolean containsKey(Object key) {
-        return getNode(hash(key), key) != null;
+        return !isEmpty() && getNode(hash(key), key) != null;
     }
 
     /**
@@ -1141,7 +1141,7 @@
     @Override
     public V getOrDefault(Object key, V defaultValue) {
         Node<K,V> e;
-        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
+        return isEmpty() || (e = getNode(hash(key), key)) == null ? 
defaultValue : e.value;
     }
 
     @Override
diff -r f143729ca00e src/java.base/share/classes/java/util/LinkedHashMap.java
--- a/src/java.base/share/classes/java/util/LinkedHashMap.java  Wed May 13 
16:18:16 2020 +0200
+++ b/src/java.base/share/classes/java/util/LinkedHashMap.java  Tue May 19 
19:36:12 2020 +0200
@@ -438,7 +438,7 @@
      */
     public V get(Object key) {
         Node<K,V> e;
-        if ((e = getNode(hash(key), key)) == null)
+        if (isEmpty() || (e = getNode(hash(key), key)) == null)
             return null;
         if (accessOrder)
             afterNodeAccess(e);
@@ -450,7 +450,7 @@
      */
     public V getOrDefault(Object key, V defaultValue) {
        Node<K,V> e;
-       if ((e = getNode(hash(key), key)) == null)
+       if (isEmpty() || (e = getNode(hash(key), key)) == null)
            return defaultValue;
        if (accessOrder)
            afterNodeAccess(e);

Reply via email to