Map不常用的几个api

2022/05/03 Java 共 4695 字,约 14 分钟

前言

看了看jdk的源码,果然有很多收获。Map的Api很多,但我在平时使用的只有其中很少的一部分,有些逻辑其实已经在jdk中封装的很好了,如果熟练使用能简化很多麻烦,把很多逻辑扔给这些api而不是自己在业务逻辑中维护,代码能清晰简洁很多。

总结表格

 plainifEqulsIfAbsentIfPresentall
getV get(Object var1); V getOrDefault(Object var1, V var2);  
putV put(K var1, V var2); V putIfAbsent(K var1, V var2);  
removeV remove(Object var1);boolean remove(Object var1, Object var2);   
replaceV replace(K var1, V var2) ;boolean replace(K var1, V var2, V var3);  void replaceAll(BiFunction<? super K, ? super V, ? extends V> var1);
computeV 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;
    }

putIfAbsentmap.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源码确实得认真看啊,垃圾八股文总结的头头是道问题是不中用啊,不如看两遍。

文档信息

Search

    Table of Contents