Java – what makes HashMap Putifabsent is faster than containskey?

topic

How can the HashMap method putifabsent conditionally execute put faster than before calling containskey (x)?

For example, if you do not use putifabsent, you can use:

if(!map.containsKey(x)){ 
   map.put(x,someValue); 
}

I thought putifabsent was a convenient method to call containskey and put it on HashMap However, after running the benchmark, putifabsent is significantly faster than using containskey followed by put I checked Java Util source code, try to see what's going on, but it's a little too mysterious for me Does anyone know that putifabsent seems to work with better time complexity? This is my assumption based on running some code tests, in which my code runs 50% faster when using putifabsent It seems to avoid calling get (), but how?

example

if(!map.containsKey(x)){
     map.put(x,someValue);
}

VS

map.putIfAbsent(x,somevalue)

Hashmap. Putifabsent java source code

@Override
public V putIfAbsent(K key,V value) {
    return putVal(hash(key),key,value,true,true);
}

final V putVal(int hash,K key,V value,boolean onlyIfAbsent,boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n,i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash,null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this,tab,hash,value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash,null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab,hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

Solution

The HashMap implementation of putifabsent only searches for the key once. If the key cannot be found, the value is put into the relevant bin (already found) This is what putval does

On the other hand, use map Containskey (x) followed by map Put (x, somevalue) performs a lookup on the key in the map twice, which takes more time

Note that put also calls putval (put calls putval (hash (key), false, true) and putifabsent calls putval (hash (key), true)), so putifabsent has the same performance and calls just put, which is faster than calling containskey and put

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>