专栏名称: Java基基
一个苦练基本功的 Java 公众号,所以取名 Java 基基
目录
相关文章推荐
内江头条  ·  4400亿元!雷军成中国新首富! ·  昨天  
内江头条  ·  4400亿元!雷军成中国新首富! ·  昨天  
西安晚报  ·  雷军,新首富! ·  昨天  
融媒吴江  ·  名单公布!被依法处置! ·  昨天  
融媒吴江  ·  名单公布!被依法处置! ·  昨天  
51好读  ›  专栏  ›  Java基基

Map 只会 put、get?快来学这几个“新”方法!

Java基基  · 公众号  · 科技自媒体  · 2024-12-14 18:27

主要观点总结

文章介绍了JDK8中Map的新方法,包括getOrDefault、foreach、merge、putIfAbsent、computer、computeIfAbsent、computeIfPresent和replace等,并给出了使用示例。同时,推荐了一个基于Spring Boot + MyBatis Plus + Vue & Element实现的后台管理系统项目,并提供了项目地址和视频教程。最后,鼓励读者加入其知识星球,以提升技术能力。

关键观点总结

关键观点1: JDK8中Map的新方法简介和使用示例

文章介绍了JDK8中Map的七个新方法,包括getOrDefault、foreach、merge、putIfAbsent、computer、computeIfAbsent和computeIfPresent,并给出了每个方法的使用示例和场景描述。

关键观点2: 基于Spring Boot + MyBatis Plus + Vue & Element的后台管理系统介绍

文章推荐了一个基于Spring Boot + MyBatis Plus + Vue & Element实现的后台管理系统项目,支持RBAC动态权限、多租户、数据权限等功能,并提供了项目地址和视频教程。

关键观点3: 鼓励读者加入知识星球

文章最后鼓励读者加入作者的知识星球,以提升技术能力,并介绍了加入方式以及星球的内容。


正文

👉 这是一个或许对你有用 的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入 芋道快速开发平台 知识星球。 下面是星球提供的部分资料:

👉 这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本

来源:juejin.cn/post/
7342420969879093299


引子

Map的数据操作,你是不是还只会 put get ?Map是我们日常编程中十分常用的数据接口,的在JDK8中,Map引入了几个新方法,可以简化我们对Map中数据的操作。目前JDK的最新LTS版本已经更新到21了,这几个在JDK8引入的Map”新“方法其实也是”老“方法了,还没熟练使用也太out了,快来看看你都”学废“了吗?

getOrDefault

这个方法名很直观,见名知意:尝试获取key对应的值,如果未获取到,就返回默认值。看一个使用的例子,新写法会比老写法更加简洁:

private static void testGetOrDefault() {
    Map map = new HashMap<>(4);
    map.put("123""123");
    String key = "key";
    String defaultValue = "defaultValue";

    // 老写法
    String oldValue = defaultValue;
    if (map.containsKey(key)) {
        oldValue = map.get(key);
    }
    System.out.println("oldValue = " + oldValue);

    // 新写法
    String newValue = map.getOrDefault(key, defaultValue);
    System.out.println("newValue = " + newValue);
}

foreach

看方法名也可以知道,这个方法是遍历map的数据使用的。如果没有foreach,我们遍历map的时候一般是使用增强for循环,有了这个方法后,可以更加方便使用entry中的key和val:

private static void testForeach() {
        Map map = new HashMap<>(4);
        map.put("123""123");

        // 老写法
        for (Map.Entry entry : map.entrySet()) {
            System.out.printf("老写法 key = %s, value = %s%n", entry.getKey(), entry.getValue());
        }

        // 新写法
        map.forEach((key, value) -> System.out.printf("新写法 key = %s, value = %s%n", key, value));
    }

merge

从名字可以想到,是合并entry使用的,但是具体是怎么合并呢?看一下日常最常用的Map实现类HashMap对merge方法的实现

@Override
public V merge(K key, V value,
               BiFunction super V, ? super V, ? extends V> remappingFunction)
 
{
    if (value == null || remappingFunction == null)
        throw new NullPointerException();
    int hash = hash(key);
    Node[] tab; Node first; int n, i;
    int binCount = 0;
    TreeNode t = null;
    Node 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)first).getTreeNode(hash, key);
        else {
            Node 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);
        }
    }
    if (old != null) {
        V v;
        if (old.value != null) {
            int mc = modCount;
            v = remappingFunction.apply(old.value, value);
            if (mc != modCount) {
                throw new ConcurrentModificationException();
            }
        } else {
            v = value;
        }
        if (v != null) {
            old.value = v;
            afterNodeAccess(old);
        }
        else
            removeNode(hash, key, nullfalsetrue);
        return v;
    } else {
        if (t != null)
            t.putTreeVal(this, tab, hash, key, value);
        else {
            tab[i] = newNode(hash, key, value, first);
            if (binCount >= TREEIFY_THRESHOLD - 1)
                treeifyBin(tab, hash);
        }
        ++modCount;
        ++size;
        afterNodeInsertion(true);
        return value;
    }
}

代码比较长,但是实现的效果比较容易描述:这个方法接收3个参数: key value function

  • 如果key存在,将value按照function做1次计算后,更新到Map中
  • 如果key不存在,将key-value放入Map中

这个方法在某些场景中挺好用的,代码简洁易懂,例如:我们有1个List,要统计List中每个元素出现的次数。我们要实现的逻辑是,遍历List中的每个元素,如果这个元素在Map中存在,Map中的值+1;如果不存在,则放入Map中,次数(值)为1。

private static void testMerge() {
        Map cntMap = new HashMap<>(8);
        List list = Arrays.asList("apple""orange""banana""orange");

        // 老写法
        for (String item : list) {
            if (cntMap.containsKey(item)) {
                cntMap.put(item, cntMap.get(item) + 1);
            } else {
                cntMap.put(item, 1);
            }
        }

        // 新写法
        for (String item : list) {
            cntMap.merge(item, 1, Integer::sum);
        }
    }

可以看到我们使用merge方法的话,只用1行就简洁实现了这个逻辑。

putIfAbsent

也是一个见名知意的方法:不存在key或者值为null时,才将键值对放入Map。跟 put 方法相比,这个方法不会直接覆盖已有的值,在不允许覆盖旧值的场景使用起来会比较简洁。

private static void testPutIfAbsent() {
    Map scoreMap = new HashMap<>(4);
    scoreMap.put("Jim"88);
    scoreMap.put("Lily"90);

    // 老写法
    if (!scoreMap.containsKey("Lily")) {
        scoreMap.put("Lily"98);
    }

    // 新写法
    scoreMap.putIfAbsent("Lily"98);
}

computer

computer方法需要传入2个参数: key function 。主要有3步操作

  1. 获取到key对应的oldValue,可能为null
  2. 经过function计算获取newValue
  3. put(key, newValue)

还是以刚刚统计单次次数需求为例,看一下computer的写法:

private static void testComputer() {
        Map cntMap = new HashMap<>(8);
        List list = Arrays.asList("apple""orange""banana""orange");

        // 老写法
        for (String item : list) {
            if (cntMap.containsKey(item)) {
                cntMap.put(item, cntMap.get(item) + 1);
            } else {
                cntMap.put(item, 1);
            }
        }

        // 新写法
        for (String item : list) {
            cntMap.compute(item, (k, v) -> {
                if (v == null) {
                    v = 1;
                } else {
                    v += 1;
                }
                return v;
            });
        }
    }

computeIfAbsent

看名字就知道是 compute 方法衍生出来的方法,这个方法只在key不存在的时候,执行computer计算,如果说key对应的value存在,就直接返回这个value。例如,我们需要计算斐波那锲数列的时候,可以使用这个方法来简化代码:







请到「今天看啥」查看全文