getOrDefault方法
这个很好理解,如果get(key)
为空,就返回传入的默认值,否则直接返回。
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
putIfAbsent方法
这个很好理解,如果当前key对应value为空,就进行put。否则不做事。
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
merge方法
这个方法传入的是key, value
,如果 oldValue
为空,那入参value
就直接赋值给newValue
,否则就执行lambda表达式的计算,如果计算出的结果为空,就执行key的删除。
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if (newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
compute方法
直接看代码
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
//通过传入的函数式接口计算出新value
V newValue = remappingFunction.apply(key, oldValue);
//如果新value为空,否则什么也不做。
if (newValue == null) {
// 旧value不为空,或者map中存在当前key就删除(这个是考虑key对应的oldValue就是null)
if (oldValue != null || containsKey(key)) {
remove(key);
return null;
} else {
//否则什么也不做
return null;
}
} else {
//如果新value不为空,就相当于普通的put方法
put(key, newValue);
return newValue;
}
}
所以compute方法就是给它一个键和lambda表达式(函数式接口Function应该都知道,BiFunction就是两个参数的Function接口),如果这个lambda表达式计算出的结果为null,就进行map的删除,否则就进行普通的put。
所以merge和compute方法的区别就是在入参
、lambda表达式
和在remove(key)
时的区别。
- merge可以手动设置一个入参value,方便外部设置。lambda表达式的参数是入参val和oldVal。在
remove(key)
时不会检查map中是否存在key
。 - compute入参没有value。lambda表达式的参数是key和oldVal。在
remove(key)
时会检查map中是否存在key,如果不存在就不执行删除。不过compute这个return写的真难看。。直接和merge一样最后写return不就好了。。
举个例子,比如要统计每个元素出现的次数。
public static void main(String[] args) throws IOException {
Map<Integer, Integer> map = new HashMap<>();
int[] nums = {
1, 2, 3, 1, 42, 32, 33, 131, 131, 2, 3, 3, 3, 1, 3, 42};
//如果你不知道getOrDefault就可能会这样做
for (int num : nums) {
Integer cnt = map.get(num);
if (cnt == null) map.put(num, 1);
else map.put(num, cnt + 1);
}
//如果你知道可能会这样做
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
//如果你知道merge,可以这样
for (int num : nums) {
map.merge(num, 1, (old, val) -> old + val);
}
//如果你知道compute,那还可以这样做。
//这里看着比上面还长,但是如果在计算新value的时候如果需要同时用到
//oldValue和key那么这个方法就可以省去一些判断
for (int num : nums) {
map.compute(num, (key, old) -> old == null ? 1 : old + 1);
}
}
computeIfAbsent方法
这个方法看名字也容易理解,如果key对应的value为null才进行操作,否则什么也不做。
但是和compute方法有区别,计算新value的时候参数只有key,也就是传入的key。
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
//通过key计算出新value,并且新value不为null时才进行put
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
computeIfPresent方法
和上面的相反,如果通过传入的key得到的value不为空才进行操作,否则什么也不做。
和compute方法一样,计算新value时参数是两个,分别为传入的key和oldValue。
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
if ((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue);
//如果新value
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
remove(key);
return null;
}
} else {
return null;
}
}
replace方法
key对应的value如果和oldValue相同,就替换为newValue,否则不做事。
default boolean replace(K key, V oldValue, V newValue) {
Object curValue = get(key);
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
put(key, newValue);
return true;
}