merge()方法比compute()多传入一个value参数,根据value参数判断是否新建节点。
merge()方法功能:
如果key存在的情况下: value不为空,remappingFunction的apply()执行结果不为空,替换value为apply()执行结果的值; value不为空,remappingFunction的apply()执行结果为空,删除key节点; value为空:抛出java.lang.NullPointerException异常 old=查找出的key节点,如果old.value=null,不执行apply,会把value赋值给v, 再把v赋值给old.value; key不存在的情况:此时old为空,value不为空,不管remappingFunction的apply()执行完是否为空 都新建(key,value)节点,此时remappingFunction无效,不执行;
下面看具体注释
/*
* merge功能:
* 如果key存在的情况下:
* value不为空,remappingFunction的apply()执行结果不为空,替换value为apply()执行结果的值;
* value不为空,remappingFunction的apply()执行结果为空,删除key节点;
* value为空:抛出java.lang.NullPointerException异常
* old=查找出的key节点,如果old.value=null,不执行apply,会把value赋值给v,再把v赋值给old.value;
* key不存在的情况:此时old为空,value不为空,不管remappingFunction的apply()执行完是否为空
* 都新建(key,value)节点,此时remappingFunction无效,不执行;
* */
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (value == null) //传入参数value不能为空,否则报空指针
throw new NullPointerException();
if (remappingFunction == null)//如果自定义函数为空,抛出异常
throw new NullPointerException();
int hash = hash(key);//算出给定key的hash值
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
HashMap.TreeNode<K,V> t = null;//定义Node类型的数组tab、节点first,n,i;
Node<K,V> old = null;//定义Node节点old,找到数组或红黑树或链表中和给定的key相同的节点时,赋值给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值,可为空可不为空,value为空走,else {v = value; }
// key不存在时直接判断old是否为空
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);//循环遍历链表上的节点
}
}
if (old != null) { //如果key在tab中不存在,走这里,第一次old肯定为null,old.value也为null,直接到if (value != null)新建节点;
V v;//定义v;
if (old.value != null) { //如果old.value不为空,执行自定义函数remappingFunction.apply();
int mc = modCount;//定义计数变量mc=hashMap结构修改的记录次数modCount
v = remappingFunction.apply(old.value, value);//调用自定义函数的apply()方法,把执行结果赋值给v;
if (mc != modCount) {//如果modCount不等于mc,说明有其它线程修改这个hashMap,抛出异常
throw new ConcurrentModificationException();
}
} else {//如果old.valu为null,走到这里说明key存在,但是key对应的value=null,此时把传入参数value赋值给v;
v = value;//此时把传入参数value赋值给v;
}
if (v != null) { //如果v不为空
old.value = v; //把v赋值给key对应节点的value;
afterNodeAccess(old);//回调函数
}
else//如果v为空即调用自定义函数的apply()方法,把执行结果为空,则删除key对应的节点;
removeNode(hash, key, null, false, true);//删除key对应的节点;
return v;//返回v
}
if (value != null) { //如果key在tab中不存在,第一次old肯定为null,old.value也为null,走这个分支;
if (t != null) //在红黑树中根据指定的key找到一个存储位置,把这个节点赋值为t,如果t不为空;
t.putTreeVal(this, tab, hash, key, value);//把传入的key和value存入红黑树;
else {
tab[i] = newNode(hash, key, value, first);//存入数组tab
if (binCount >= TREEIFY_THRESHOLD - 1)//如果数组达到二叉树转换的临界值,则把数组tab转化为二叉树
treeifyBin(tab, hash);//走二叉树的方法;
}
++modCount;//记录hashMap的修改次数
++size;//hashMap的长度加1
afterNodeInsertion(true);//回调函数
}
return value;//value
}