前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java都21啦,8的map你用熟悉了吗

Java都21啦,8的map你用熟悉了吗

原创
作者头像
Java4ye
发布2024-02-03 10:44:07
1590
发布2024-02-03 10:44:07
举报
文章被收录于专栏:Java专栏Java专栏

Java 都更新到 21 啦。

感慨之余又想到这句,“你发任你发,我用 Java8” ,想了下,先来整理下 Java8 中 HashMap 新增的一些方法,看看自己平时工作中有用到多少~


Map 接口一览

这里 小羊 特意查看了下 1.7 和 1.8 版本的不同~ 结果发现1.8 版本多了这么的函数!(文章开始前,我列了下自己记得的。。也就 5 个🐷)

1.7和1.8 Map 接口对比
1.7和1.8 Map 接口对比

小插曲

这里简单介绍下 ComparableComparator 的区别 👇,后面会提到🐖

可以看到一个是 java.lang 包的,一个是 util 包的。

代码如下 👇

很明显,Comparable 属于 内部比较器, 而 Comparator 属于 外部比较器

外部比较器的好处 是我们可以有很多这种比较器,可以按排序的要求去选择 ,便于解耦。

而内部比较器也比较简单,只要实现了该 Comparable 接口就可以进行比较了。😝

代码语言:java
复制
class B implements Comparator<Integer>{
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1-o2;
    }
}
class C implements Comparable<Integer>{
    private final int num;
    public C(int num){
        this.num=num;
    }
    @Override
    public int compareTo(Integer o) {
        return this.num-o;
    }
}

Entry

那么,我们先从 内部类 Entry 开始叭~

从上面的图中,我们发现 1.8 中多了四个 comparing 开头的方法,而且返回值都是 Comparator 类型的。🐖

comparingByKey

代码语言:java
复制
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
    return (Comparator<Map.Entry<K, V>> & Serializable)
        (c1, c2) -> c1.getKey().compareTo(c2.getKey());
}

一眼看过去,就觉得这个函数好复杂的样子😱

下面来一步步解析~ 🐖

  1. 从函数名可以得知它的主要作用应该是 按照 key 自然排序
  2. 再仔细看看它,发现是一个 泛型方法 ,主要说明 K 的上限是 Comparable (K必须实现这个接口)
  3. 再瞅瞅 return 语句中,居然有这么一个 & 符号(居然还能这么写😄), 猜测这里应该得同时实现 Comparator 和 Serializable 接口。
  4. 最后就一个常见的 lambda 表达式了,重写了 Comparator 中的 compare 方法
  5. 最后读读这个方法注释确认下

可以通过 stream 来使用 comparingByKey 进行排序。

代码语言:java
复制
List<Map.Entry<String, Integer>> collect = map.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(
        Collectors.toList()
);

comparingByValue 也一样,这两个都是使用 内部比较器 Comparable

还有两个使用 外部比较器 Comparator 的例子,就不多介绍了。

在代码中搜索了 1.8 后,发现总共有15个,除去上面 4 个 外,说明还有 11 个待介绍~ 😱

getOrDefault

可以发现 当这个 value 不为 null 时,或者 map 中有这个 key 时,就直接返回这个 value。

而不是说 value 不为 null 时才返回 value 的

tip:

使用时也得注意处理这个 null 的情况!!

例子

代码语言:java
复制
map.getOrDefault("Java4ye",2)

forEach

代码语言:java
复制
default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k;
        V v;
        try {
            k = entry.getKey();
            v = entry.getValue();
        } catch(IllegalStateException ise) {
            // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }
        action.accept(k, v);
    }
}

可以看到 forEach 中也是直接获取这个 entrySet() ,然后去处理每一个 key,value。

例子如下 👇

tip:

BiConsumerConsumer 接口类似,只不过它是接受 两个参数 ,而 Consumer 是一个。

认准 Bi 开头的,表示接受两个参数,其余效果和那 四大函数式接口一样。(下文就不多介绍了)🐖

replaceAll

代码语言:java
复制
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
    Objects.requireNonNull(function);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k;
        V v;
        try {
            k = entry.getKey();
            v = entry.getValue();
        } catch(IllegalStateException ise) {
            // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }

        // ise thrown from function is not a cme.
        v = function.apply(k, v);

        try {
            entry.setValue(v);
        } catch(IllegalStateException ise) {
            // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }
    }
}

这个方法的重点在 v = function.apply(k, v); 和 entry.setValue(v); 这两句上。

主要作用就是处理这个 value,然后再重新设置到 entry 中。

这里的 replaceAll 的含义应该是 replaceAllValue , 替换掉原先所有的 value。

例子 👇

代码语言:java
复制
private static void replaceAll(Map<String, Integer> map) {
    map.replaceAll(
            (k, v) -> {
                if (v != null) {
                    v++;
                } else {
                    v = 0;
                }
                return v;
            }
    );
}

putIfAbsent

代码语言:java
复制
default V putIfAbsent(K key, V value) {
    V v = get(key);
    if (v == null) {
        v = put(key, value);
    }

    return v;
}

这个就很简单了,如果值为 null 的话,就设置进去。

但是要注意它的返回值 是旧值。

remove

代码语言:java
复制
default boolean remove(Object key, Object value) {
    Object curValue = get(key);
    if (!Objects.equals(curValue, value) ||
        (curValue == null && !containsKey(key))) {
        return false;
    }
    remove(key);
    return true;
}

这里在原有 remove 方法的基础上,多增加了一层判断。

就是当当前值 curValue 和期望值 value 相等且 map 中存在这个 key 时才去删除

可以看到注释中有常规的做法 👇

replace

这两个也很简单,在 基础条件:有这个 key 的基础上,再多加一个条件,或者不加条件。和 remove 方法近似。

代码语言:java
复制
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;
}

当有这个 key 且 旧值等于期望值时才替换。


代码语言:java
复制
default V replace(K key, V value) {
    V curValue;
    if (((curValue = get(key)) != null) || containsKey(key)) {
        curValue = put(key, value);
    }
    return curValue;
}

这个是 key存在时就替换。🐷

不过我发现它们都喜欢返回 旧值 的,小伙伴们也要留意下~

computeIfAbsent

代码语言:java
复制
default V computeIfAbsent(K key,
        Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v;
    if ((v = get(key)) == null) {
        V newValue;
        if ((newValue = mappingFunction.apply(key)) != null) {
            put(key, newValue);
            return newValue;
        }
    }

    return v;
}

当不存在时(指 key 不存在 或者 value 为 null 的情况),通过 Function 去获取这个 返回值,而且当这个 返回值不为 null 时,put 到 map 中。

computeIfPresent

代码语言:java
复制
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);
        if (newValue != null) {
            put(key, newValue);
            return newValue;
        } else {
            remove(key);
            return null;
        }
    } else {
        return null;
    }
}

存在时去算出这个新值,然后替换进去,和上面那个差不多。🐷

例子👇

compute

代码语言:java
复制
default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        V oldValue = get(key);

        V newValue = remappingFunction.apply(key, oldValue);
        if (newValue == null) {
            // delete mapping
            if (oldValue != null || containsKey(key)) {
                // something to remove
                remove(key);
                return null;
            } else {
                // nothing to do. Leave things as they were.
                return null;
            }
        } else {
            // add or replace old mapping
            put(key, newValue);
            return newValue;
        }
    }

这个是我目前看到的最复杂的一个了😂,看方法名都不知道他要干嘛

看了注释后发现它主要有下面两个功能 👇

当 旧值不为 null 新值 为 null 时,删除该 key。 新值不为 null 时,设置到 map 中。

小例子如下 👇 (重新计算对应 Key 的 value 值。)

代码语言:java
复制
map.compute(4L, (k, v) -> {
    if (v == null) {
        v = 1;
    } else {
        v++;
    }
    return v;
});

merge

代码语言:java
复制
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;
}

看过上面那个方法后,感觉这个居然清晰多了😄

当 新值 为 null 时,删除该 key。 当 旧值 为 null 时,新值 = value 当 旧值 不为 null 时, 和 value 一起计算,得出 新值。

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Map 接口一览
  • 小插曲
  • Entry
  • comparingByKey
  • getOrDefault
  • forEach
  • replaceAll
  • putIfAbsent
  • remove
  • replace
  • computeIfAbsent
  • computeIfPresent
  • compute
  • merge
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档