前言
看了看jdk的源码,果然有很多收获。Map的Api很多,但我在平时使用的只有其中很少的一部分,有些逻辑其实已经在jdk中封装的很好了,如果熟练使用能简化很多麻烦,把很多逻辑扔给这些api而不是自己在业务逻辑中维护,代码能清晰简洁很多。
总结表格
plain | ifEquls | IfAbsent | IfPresent | all | |
---|---|---|---|---|---|
get | V get(Object var1); | V getOrDefault(Object var1, V var2); | |||
put | V put(K var1, V var2); | V putIfAbsent(K var1, V var2); | |||
remove | V remove(Object var1); | boolean remove(Object var1, Object var2); | |||
replace | V replace(K var1, V var2) ; | boolean replace(K var1, V var2, V var3); | void replaceAll(BiFunction<? super K, ? super V, ? extends V> var1); | ||
compute | V compute(K var1, BiFunction<? super K, ? super V, ? extends V> var2) { | V computeIfAbsent(K var1, Function<? super K, ? extends V> var2) | V computeIfPresent(K var1, BiFunction<? super K, ? super V, ? extends V> var2) { |
源码
jdk1.8。
public interface Map<K, V> {
……
}
很多方法都是后来加在map这个接口里的default方法。
特别注意一下: 由于存在map.put(key, null);
这种情况,这些方法分别都做了处理。
get
V get(Object var1);
default V getOrDefault(Object var1, V var2) {
Object var3;
return (var3 = this.get(var1)) == null && !this.containsKey(var1) ? var2 : var3;
}
getOrDefault
我也归到IfAbsent类了, 但逻辑稍微有点不一样,如果缺失是返回默认值,而其他的IfAbsent是只有Absent的时候才进行逻辑。
put
V put(K var1, V var2);
default V putIfAbsent(K var1, V var2) {
Object var3 = this.get(var1);
if (var3 == null) {
var3 = this.put(var1, var2);
}
return var3;
}
putIfAbsent
在map.put(key, null);
情况下也会put。
remove
V remove(Object var1);
default boolean remove(Object var1, Object var2) {
Object var3 = this.get(var1);
if (Objects.equals(var3, var2) && (var3 != null || this.containsKey(var1))) {
this.remove(var1);
return true;
} else {
return false;
}
}
remove(Object var1, Object var2)
在map.put(key, null);
情况不会remove。
replace
// 返回replace后填入的value,也就是get这个key会得到的
default V replace(K var1, V var2) {
Object var3;
if ((var3 = this.get(var1)) != null || this.containsKey(var1)) {
var3 = this.put(var1, var2);
}
return var3;
}
// 返回是否成功replace
default boolean replace(K var1, V var2, V var3) {
Object var4 = this.get(var1);
if (Objects.equals(var4, var2) && (var4 != null || this.containsKey(var1))) {
this.put(var1, var3);
return true;
} else {
return false;
}
}
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> var1) {
Objects.requireNonNull(var1);
Iterator var2 = this.entrySet().iterator();
while(var2.hasNext()) {
Entry var3 = (Entry)var2.next();
Object var4;
Object var5;
try {
var4 = var3.getKey();
var5 = var3.getValue();
} catch (IllegalStateException var8) {
throw new ConcurrentModificationException(var8);
}
var5 = var1.apply(var4, var5);
try {
var3.setValue(var5);
} catch (IllegalStateException var7) {
throw new ConcurrentModificationException(var7);
}
}
}
前两个方法在map.put(key, null);
的情况下也会replace。
replaceAll
对整个map的value作了一次处理,因为有遍历还做了下并发的安全,很细啊。
compute
// 返回值是key最后对应的value
default V computeIfAbsent(K var1, Function<? super K, ? extends V> var2) {
Objects.requireNonNull(var2);
Object var3;
Object var4;
if ((var3 = this.get(var1)) == null && (var4 = var2.apply(var1)) != null) {
this.put(var1, var4);
return var4;
} else {
return var3;
}
}
// 如果最后计算出null,会remove这个key
// key最后对应的value
default V computeIfPresent(K var1, BiFunction<? super K, ? super V, ? extends V> var2) {
Objects.requireNonNull(var2);
Object var3;
if ((var3 = this.get(var1)) != null) {
Object var4 = var2.apply(var1, var3);
if (var4 != null) {
this.put(var1, var4);
return var4;
} else {
this.remove(var1);
return null;
}
} else {
return null;
}
}
// 如果最后计算出null,会remove这个key
// 否则无论这个key原来是否有,都put
// 返回key最后对应的value
default V compute(K var1, BiFunction<? super K, ? super V, ? extends V> var2) {
Objects.requireNonNull(var2);
Object var3 = this.get(var1);
Object var4 = var2.apply(var1, var3);
if (var4 == null) {
if (var3 == null && !this.containsKey(var1)) {
return null;
} else {
this.remove(var1);
return null;
}
} else {
this.put(var1, var4);
return var4;
}
}
可以这么理解,compute是key参与运算的replace。
merge
// 返回计算的结果,也就是这个key最后对应的value
default V merge(K var1, V var2, BiFunction<? super V, ? super V, ? extends V> var3) {
Objects.requireNonNull(var3);
Objects.requireNonNull(var2);
Object var4 = this.get(var1);
Object var5 = var4 == null ? var2 : var3.apply(var4, var2);
if (var5 == null) {
this.remove(var1);
} else {
this.put(var1, var5);
}
return var5;
}
merge特殊一点,感觉上像是合并同一个key有关系的不同的两个值,这两个值可以由一个BiFnction合并,然后构建一个map。
比如计算一个人的总工资,总成绩之类。
forEach
default void forEach(BiConsumer<? super K, ? super V> var1) {
Objects.requireNonNull(var1);
Object var4;
Object var5;
for(Iterator var2 = this.entrySet().iterator(); var2.hasNext(); var1.accept(var4, var5)) {
Entry var3 = (Entry)var2.next();
try {
var4 = var3.getKey();
var5 = var3.getValue();
} catch (IllegalStateException var7) {
throw new ConcurrentModificationException(var7);
}
}
对Map的每个Entry做一下处理,把key和value传给一个Biconsumer。
顺便把map的遍历贴一下把,这个老生常谈了,无论是用keySet还是Entry都挺好使的。
1. keySet
for (String key : map.keySet()) {
}
2. Iterator
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
}
3. values
for (String v : map.values()) {
}
感想
看代码的时候突然萌生了点想法,分享一下。
函数式在这些方法里面已经运用的十分顺畅了,老是有人提到函数式就是lambda,java的函数式的实现仍然是OOP的,是属于java的独特的方法。我们使用的媒介是加了@FunctionalInterface
的一个接口,我们并不是将一个函数作为参数传入的(像其他语言实现的那样),而是将一个实现了对应接口的类作为参数传入的。
这个参数首先是一个类,再其次在结构上是一个匿名内部类,最后,被简化成了一个lambda表达式。
还有,jdk源码确实得认真看啊,垃圾八股文总结的头头是道问题是不中用啊,不如看两遍。
文档信息
- 本文作者:nyaaar
- 本文链接:https://nyaaarlathotep.github.io/2022/05/03/Map%E4%B8%8D%E5%B8%B8%E7%94%A8%E7%9A%84%E5%87%A0%E4%B8%AAapi/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)