1. compute
- 指定 key,找到对应的Node节点,执行remappingFunction.apply(key,value),返回新的 value 值,会出现四种情况
- Node 为 null,value为 null :不用进行操作,返回 value
- Node 不为 null,value为 null :删除 Node 节点,返回 value
- Node 为 null,value 不为 null :新建节点(key, value),返回 value
- Node 不为 null,value 不为 null :更新Node节点的值,返回 value
@Override
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (remappingFunction == null)
throw new NullPointerException();
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null;
if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length;
if ((first = tab[i = (n - 1) & hash]) != null) {
if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
else {
Node<K,V> e = first; K k;
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e;
break;
}
++binCount;
} while ((e = e.next) != null);
}
}
V oldValue = (old == null) ? null : old.value;
V v = remappingFunction.apply(key, oldValue);
if (old != null) {
if (v != null) {
old.value = v;
afterNodeAccess(old);
}
else
removeNode(hash, key, null, false, true);
}
else if (v != null) {
if (t != null)
t.putTreeVal(this, tab, hash, key, v);
else {
tab[i] = newNode(hash, key, v, first);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
++modCount;
++size;
afterNodeInsertion(true);
}
return v;
}
2. computeIfAbsent
- 指定 key,找到对应的Node节点,执行remappingFunction.apply(key),返回新的 value 值,会执行以下四种情况:
- Node 不为 null 且 Node.value 不为null,返回 Node.value
- value 为 null,直接返回 null
- value 不为null,Node不为null 且 Node.value为null,设置 Node.value为value,返回 value
- value 不为null,Node为null,新建节点 (key, v), 返回 value
@Override
public V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
if (mappingFunction == null)
throw new NullPointerException();
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null;
if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length;
if ((first = tab[i = (n - 1) & hash]) != null) {
if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
else {
Node<K,V> e = first; K k;
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e;
break;
}
++binCount;
} while ((e = e.next) != null);
}
V oldValue;
if (old != null && (oldValue = old.value) != null) {
afterNodeAccess(old);
return oldValue;
}
}
V v = mappingFunction.apply(key);
if (v == null) {
return null;
} else if (old != null) {
old.value = v;
afterNodeAccess(old);
return v;
}
else if (t != null)
t.putTreeVal(this, tab, hash, key, v);
else {
tab[i] = newNode(hash, key, v, first);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
++modCount;
++size;
afterNodeInsertion(true);
return v;
}
3. computeIfPresent
- 找不到 key 对应的 Node 节点 || Node.value 为 null,直接返回 null
- 执行指定动作返回 value,若 value 为 null ,删除 key 对应的 Node 节点返回null,否则,替换旧值为value并返回 value
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (remappingFunction == null)
throw new NullPointerException();
Node<K,V> e; V oldValue;
int hash = hash(key);
if ((e = getNode(hash, key)) != null &&
(oldValue = e.value) != null) {
V v = remappingFunction.apply(key, oldValue);
if (v != null) {
e.value = v;
afterNodeAccess(e);
return v;
}
else
removeNode(hash, key, null, false, true);
}
return null;
}
4. 代码小结
4.1 compute()、computeIfAbsent()、computeIfPresent() 的使用
import java.util.HashMap;
public class HashMapTest06 {
public static void main(String[] args) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
for(int i = 1; i <= 8; i++) {
hashMap.put(i, i);
}
System.out.println("now hashmap: " + hashMap);
System.out.println("=============== compute ============");
System.out.println("hashMap.compute(10, (k, v) -> null): " + hashMap.compute(10, (k, v) -> null));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.compute(1, (k, v) -> null): " + hashMap.compute(1, (k, v) -> null));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.compute(10, (k, v) -> 10): " + hashMap.compute(10, (k, v) -> 10));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.compute(2, (k, v) -> 20): " + hashMap.compute(2, (k, v) -> 20));
System.out.println("now hashmap: " + hashMap);
System.out.println("=============== computeIfAbsent ============");
hashMap.put(50, null);
System.out.println("hashMap.put(50, null), now hashmap: " + hashMap);
System.out.println("hashMap.computeIfAbsent(3, (k) -> 30): " + hashMap.computeIfAbsent(3, (k) -> 30));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.computeIfAbsent(50, (k) -> null): " + hashMap.computeIfAbsent(50, (k) -> null));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.computeIfAbsent(50, (k) -> 50): " + hashMap.computeIfAbsent(50, (k) -> 50));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.computeIfAbsent(9, (k) -> 9): " + hashMap.computeIfAbsent(9, (k) -> 9));
System.out.println("now hashmap: " + hashMap);
System.out.println("=============== computeIfPresent ============");
hashMap.put(100, null);
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.computeIfPresent(20, (k, v) -> 20): " + hashMap.computeIfPresent(20, (k, v) -> 20));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.computeIfPresent(100, (k, v) -> 100): " + hashMap.computeIfPresent(100, (k, v) -> 100));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.computeIfPresent(6, (k, v) -> 60): " + hashMap.computeIfPresent(6, (k, v) -> 60));
System.out.println("now hashmap: " + hashMap);
System.out.println("hashMap.computeIfPresent(7, (k, v) -> null): " + hashMap.computeIfPresent(7, (k, v) -> null));
System.out.println("now hashmap: " + hashMap);
}
}
now hashmap: {1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8}
=============== compute ============
hashMap.compute(10, (k, v) -> null): null
now hashmap: {1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8}
hashMap.compute(1, (k, v) -> null): null
now hashmap: {2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8}
hashMap.compute(10, (k, v) -> 10): 10
now hashmap: {2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 10=10}
hashMap.compute(2, (k, v) -> 20): 20
now hashmap: {2=20, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 10=10}
=============== computeIfAbsent ============
hashMap.put(50, null), now hashmap: {2=20, 50=null, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 10=10}
hashMap.computeIfAbsent(3, (k) -> 30): 3
now hashmap: {2=20, 50=null, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 10=10}
hashMap.computeIfAbsent(50, (k) -> null): null
now hashmap: {2=20, 50=null, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 10=10}
hashMap.computeIfAbsent(50, (k) -> 50): 50
now hashmap: {2=20, 50=50, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 10=10}
hashMap.computeIfAbsent(9, (k) -> 9): 9
now hashmap: {2=20, 50=50, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10}
=============== computeIfPresent ============
now hashmap: {2=20, 50=50, 3=3, 4=4, 100=null, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10}
hashMap.computeIfPresent(20, (k, v) -> 20): null
now hashmap: {2=20, 50=50, 3=3, 4=4, 100=null, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10}
hashMap.computeIfPresent(100, (k, v) -> 100): null
now hashmap: {2=20, 50=50, 3=3, 4=4, 100=null, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10}
hashMap.computeIfPresent(6, (k, v) -> 60): 60
now hashmap: {2=20, 50=50, 3=3, 4=4, 100=null, 5=5, 6=60, 7=7, 8=8, 9=9, 10=10}
hashMap.computeIfPresent(7, (k, v) -> null): null
now hashmap: {2=20, 50=50, 3=3, 4=4, 100=null, 5=5, 6=60, 8=8, 9=9, 10=10}
Process finished with exit code 0
4.2 使用 compute(),链节点转化为红黑树的元素 >= 8,这要与 put >= 9 区分
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class HashMapTest05 {
private static String[] base = new String[] {"Aa", "BB"};
public static List<String> generateN(int n) {
if(n <= 0) return null;
List<String> list = generateOne(null);
for(int i = 1; i < n; ++i) {
list = generateOne(list);
}
return list;
}
public static List<String> generateOne() {
return generateOne(null);
}
public static List<String> generateOne(List<String> strList) {
if((null == strList) || (0 == strList.size())) {
strList = new ArrayList<String>();
for(int i = 0; i < base.length; ++i) {
strList.add(base[i]);
}
return strList;
}
List<String> result = new ArrayList<String>();
for(int i = 0; i < base.length; ++i) {
for(String str: strList) {
result.add(base[i] + str);
}
}
return result;
}
public static void main(String[] args) throws Exception {
HashMap<String, Integer> hashMap = new HashMap<>();
Field table = hashMap.getClass().getDeclaredField("table");
Field threshold = hashMap.getClass().getDeclaredField("threshold");
table.setAccessible(true);
threshold.setAccessible(true);
List<String> list = generateN(4);
for(int i = 0; i < list.size(); i++) {
hashMap.compute(list.get(i), (key, value) -> 10);
Object[] objects = (Object[]) table.get(hashMap);
System.out.println("now objects 的长度为:" + objects.length);
System.out.println("now hashMap 有" + (i + 1) + "个元素:" + "\t");
for (Object object : objects) {
if(object == null)
System.out.print(object + "\t");
else
System.out.print(object.getClass() + "\t");
}
System.out.println();
System.out.println("=================");
}
}
}
- 输出如下:这里可以回看 03 篇,区别在于第 8 个元素的时候,compute() 进行了一次尝试树化(没成功,扩容),而 put() 在第 9 个元素的时候才尝试进行树化操作。
- 原因解释:在链条遍历时,compute() 是 first 开始遍历,bitCount ++,而 put() 是 first.next 开始遍历,bitCount ++,这就是相差为 1 的原因。
now objects 的长度为:16
now hashMap 有1个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null
=================
now objects 的长度为:16
now hashMap 有2个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null
=================
now objects 的长度为:16
now hashMap 有3个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null
=================
now objects 的长度为:16
now hashMap 有4个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null
=================
now objects 的长度为:16
now hashMap 有5个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null
=================
now objects 的长度为:16
now hashMap 有6个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null
=================
now objects 的长度为:16
now hashMap 有7个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null
=================
now objects 的长度为:32
now hashMap 有8个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有9个元素:
null null null null null null null null null class java.util.HashMap$Node null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有10个元素:
null null null null null null null null null class java.util.HashMap$TreeNode null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有11个元素:
null null null null null null null null null class java.util.HashMap$TreeNode null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有12个元素:
null null null null null null null null null class java.util.HashMap$TreeNode null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有13个元素:
null null null null null null null null null class java.util.HashMap$TreeNode null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有14个元素:
null null null null null null null null null class java.util.HashMap$TreeNode null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有15个元素:
null null null null null null null null null class java.util.HashMap$TreeNode null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
now objects 的长度为:64
now hashMap 有16个元素:
null null null null null null null null null class java.util.HashMap$TreeNode null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
=================
Process finished with exit code 0