HashMap (jdk1.8)computeIfAbsent()方法注释

computeIfAbsent 是实现Map接口中的方法,功能介绍如:

/*
    * 功能:判断给定的key在hashMap中是否存在,如果key已经存在,则返回key对应的value
    * 如果key不存在,则新生成一个节点(hash,key,value,null),value的值是通过 
    * V v = mappingFunction.apply(key);获取的,重点是要搞明白mappingFunction.apply(key)这个方法。
    * */

@Override
    public V computeIfAbsent(K key,
                             Function<? super K, ? extends V> mappingFunction) {
        if (mappingFunction == null) //如果自定义的函数为空,抛出空指针异常
            throw new NullPointerException();
        int hash = hash(key);//算出给定key的hash值
        Node<K,V>[] tab; Node<K,V> first; int n, i;//定义node类型的数组tab,node类型的节点first,定义n,i;
        int binCount = 0;//定义二叉树的计数变量
        HashMap.TreeNode<K,V> t = null;//定义TreeNode类型的对象t;
        Node<K,V> old = null;//定义存放node类型的节点old;
        if (size > threshold || (tab = table) == null ||
                (n = tab.length) == 0) //如果hashMap的长度大于扩容临界值或table及tab的长度为空,
                                        // 则走 resize(),该方法可初始化hashMap,也可以对hashMap进行扩容
            n = (tab = resize()).length;//扩容之后的tab的长度赋值给n;
        if ((first = tab[i = (n - 1) & hash]) != null) { //算出key在tab中的存储位置,如果该位置不为空,把该位置存储的节点赋值给first
                                                        //这种情况key已经存在,返回key对应的value值oldValue,key不存在时直接走
                                                        // int mc = modCount;及后面的内容,直接新建node,存入key ,value,这种情况下first为null,
            if (first instanceof HashMap.TreeNode)//判断first是否红黑树
                old = (t = (HashMap.TreeNode<K,V>)first).getTreeNode(hash, key);//走红黑树分支,找出指定key的赋值给old,t;
            else { //如果不是红黑树,走到这里就是链表
                Node<K,V> e = first; K k; //把first节点赋值给e,定义k;
                do {  //通过do-while循环,在链表中找出和给定hash值和key相同的节点,找到之后把链表上的节点e赋值给old,然后推出循环;
                    if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k)))) {
                        old = e;
                        break;
                    }
                    ++binCount; //二叉树计算变量+1;
                } while ((e = e.next) != null);//循环遍历链表上的节点
            }
            V oldValue;//定义值:oldValue;
            if (old != null && (oldValue = old.value) != null) {//红黑树和链表中如果old节点不为空且old节点的value不为空,返回old的value
                afterNodeAccess(old);//回调函数;
                return oldValue;//返回old的value
            }
        }
        int mc = modCount;//定义计数变量mc=hashMap结构修改的记录次数modCount
        /*
        * mappingFunction.apply(key)是理解整个computeIfAbsent方法的关键,apply传入的参数是key
        * apply(key)执行后返回什么?这个需看apply函数定义:  R apply(T t); 该返回值R是接口Function<T, R>的第二个参数,
        * 到这里我们在看调用函数里面传入的参数:
        * Integer integer1 = map.computeIfAbsent("4", (s)->new Integer(6));
        * 对比computeIfAbsent的方法定义:computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction)
        * 可知:key是4,s=key,也是4,Function<? super 4, ? extends V>,V对应new Integer(6)的执行结果,所以V对应的是6,
        * 所以Function<T, R> --->Function<4, 6>---> R apply(T 4),R=6;执行完mappingFunction.apply(key)的值是6,所以v=6;
        * */
        V v = mappingFunction.apply(key);//调用自定义函数mappingFunction,通过key获取key对应的value,定义返回值类型V v;
        if (mc != modCount) { throw new ConcurrentModificationException(); } //如果modCount不等于mc,说明有其它线程修改这个hashMap,抛出异常
        if (v == null) { //通过自定义函数mappingFunction获取的value为空,直接返回null;
            return null;
        } else if (old != null) {//如果old不为空,把v赋值给old的value
            old.value = v;
            afterNodeAccess(old); //回调函数
            return v; //返回v
        }
        else if (t != null)//如果在红黑树节点中找到的t节点不为空
            t.putTreeVal(this, tab, hash, key, v);//把当前的map,数组tab,hash,key,v存储到红黑树中
        else {
            tab[i] = newNode(hash, key, v, first);//在数组tab中新建节点,存入(hash, key, v, first),此时first为null,因为first = tab[i = (n - 1) & hash]) = null
            if (binCount >= TREEIFY_THRESHOLD - 1) //如果大于二叉树转换的条件,走二叉树分支
                treeifyBin(tab, hash);//把tab转换成二叉树
        }
        modCount = mc + 1;//记录hashMap的修改次数
        ++size;//hashMap的长度加1
        afterNodeInsertion(true);//回调函数
        return v;//返回v
    }

上一篇:vim 常用命令


下一篇:触发器