[项目实战] 高效使用 Map:掌握 getOrDefault、forEach 和 merge 等新方法

JDK 8 中的 Map 新方法

从 JDK 8 开始,Map 引入了几个新的方法,这些方法能够大大简化对 Map 中数据的操作。虽然它们已经引入多年,但很多开发者可能还没完全掌握这些方法。

1. getOrDefault —— 更简洁的获取值方法

getOrDefault 方法的作用是:尝试获取 key 对应的值,如果 key 不存在,则返回指定的默认值。这一方法可以让你减少 containsKey 的判断,直接在一行代码中完成操作。

示例:

private static void testGetOrDefault() {
    Map<String, String> 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);
}

通过 getOrDefault,我们能简洁地获得值,减少了 if 判断的代码量。

2. forEach —— 更简便的遍历方式

传统上,我们遍历 Map 通常会使用增强 for 循环。而 JDK 8 中引入的 forEach 方法,提供了一种更加简洁的方式来遍历 Mapkeyvalue

示例:

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

    // 老写法
    for (Map.Entry<String, String> 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));
}

forEach 方法通过 lambda 表达式,直接接受 keyvalue,使得遍历代码更加简洁和直观。

3. merge —— 合并操作的简洁实现

merge 方法的引入使得我们可以更简洁地进行合并操作。它的作用是,如果 key 已存在,则使用 BiFunction 来合并当前值和新值;如果 key 不存在,则直接将新值插入 Map

示例:

private static void testMerge() {
    Map<String, Integer> cntMap = new HashMap<>(8);
    List<String> 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,我们可以在一行代码中完成“如果存在则累加,不存在则插入”的逻辑。非常适合在统计、计数等场景中使用。

4. putIfAbsent —— 在值为 null 时才插入

putIfAbsent 方法与 put 方法的不同之处在于,它不会覆盖已经存在的 key 对应的值。只有在 Map 中不存在该 key 时,它才会插入新的键值对。这个方法在不允许覆盖已有值的场景中非常实用。

示例:

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

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

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

通过 putIfAbsent,我们能够确保不会覆盖已有的值,并且代码更加简洁。

5. compute —— 对已有值进行计算更新

compute 方法可以在 key 存在时,根据当前值和计算逻辑更新值;如果 key 不存在,则使用 function 来计算并插入新值。

示例:

private static void testCompute() {
    Map<String, Integer> cntMap = new HashMap<>(8);
    List<String> 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) -> (v == null) ? 1 : v + 1);
    }
}

compute 方法使得我们能够对已有的值进行直接计算,简化了原本需要手动判断和更新的逻辑。

6. computeIfAbsent —— 只在键不存在时计算并插入

computeIfAbsent 方法只在 Map 中不存在 key 时,使用给定的 function 来计算并插入 value。它常用于动态计算 key 对应的值。

示例:

private static void testComputeIfAbsent() {
    Map<Integer, Integer> fabMap = new ConcurrentHashMap<>(16);
    fabMap.put(0, 1);
    fabMap.put(1, 1);
    System.out.println(fab(5, fabMap));
}

private static Integer fab(Integer index, Map<Integer, Integer> fabMap) {
    return fabMap.computeIfAbsent(index, i -> fab(i - 2, fabMap) + fab(i - 1, fabMap));
}

这个方法非常适合递归计算、懒加载等场景,能确保只在 key 不存在时执行计算。

7. computeIfPresent —— 仅在键存在时计算更新

computeIfPresentcomputeIfAbsent 的姊妹方法,它只在 key 存在时执行计算,并且返回新的值。

示例:

map.computeIfPresent("key", (k, v) -> v + 1);

如果 key 存在,它会将 value 更新为计算后的结果;如果 key 不存在,则不执行任何操作。

8. replace —— 替换已存在的值

replace 方法的作用是,如果 key 存在,则更新 key 对应的 value,如果 key 不存在,则不做任何操作。它常常用来避免 key 不存在时进行不必要的插入操作。示例:

map.replace("key", 100);

如果 key 存在,则将其对应的 value 更新为 100;如果 key 不存在,replace 不会做任何事情。


总结

JDK 8 引入的这些 Map 新方法,极大地简化了我们对 Map 数据的操作。这些方法不仅提高了代码的简洁性,还能减少手动判断的次数,提高开发效率。虽然 putget 是最常用的 Map 操作,但掌握这些新方法能让我们在特定场景下事半功倍。如果你还没有熟练使用这些方法,那就赶紧来尝试一下吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值