map.merge(num, 1, Integer::sum); 和 map.put(num, map.getOrDefault(num, 0) + 1);的对比

以下是对 map.merge(num, 1, Integer::sum);map.put(num, map.getOrDefault(num, 0) + 1); 的比较:

代码示例

以下是使用 map.merge(num, 1, Integer::sum); 的示例代码:

        for (int num : nums) {
            map.merge(num,1,Integer::sum);
        }

以下是使用 map.put(num, map.getOrDefault(num, 0) + 1); 的示例代码:

        for (int num : nums) {
            map.put(num,map.getOrDefault(num,0)+1);
        }

功能解释

  • map.merge(num, 1, Integer::sum);

    • num 键不存在时,直接将键值对 (num, 1) 插入到 map 中。
    • num 键已经存在时,使用 Integer::sum 方法将旧值和新值 1 相加,更新该键的值。
  • map.put(num, map.getOrDefault(num, 0) + 1);

    • 首先使用 map.getOrDefault(num, 0) 来获取 num 的值,如果 num 键不存在,则返回默认值 0
    • 然后将获取到的值加 1,并将结果作为 num 键的新值,使用 map.put 方法存储到 map 中。

区别

  • 简洁性

    • map.merge(num, 1, Integer::sum); 更简洁,使用了 merge 方法和 Integer::sum 方法引用,代码更清晰地表达了合并的意图。
    • map.put(num, map.getOrDefault(num, 0) + 1); 相对更冗长,需要先调用 getOrDefault 然后加 1 再调用 put 方法。
  • 原子性

    • map.merge 是一个原子操作,在多线程环境下,如果多个线程同时调用 merge 方法更新同一个键的值,不会出现并发问题。
    • map.put(num, map.getOrDefault(num, 0) + 1); 不是原子操作,在多线程环境下,可能会出现并发问题。例如,线程 A 调用 map.getOrDefault(num, 0) 得到旧值,在计算 map.getOrDefault(num, 0) + 1 的过程中,线程 B 可能修改了 num 的值,导致结果不一致。

性能考虑

  • map.merge(num, 1, Integer::sum);

    • 当键不存在时,性能开销稍大,因为需要调用 merge 方法并执行合并函数(尽管合并函数很简单)。
    • 当键存在时,性能取决于合并函数的复杂程度,对于 Integer::sum 这种简单函数,性能较好。
  • map.put(num, map.getOrDefault(num, 0) + 1);

    • 对于键不存在的情况,需要调用 getOrDefault 方法,性能稍逊于 merge 方法的直接添加操作。
    • 对于键存在的情况,性能与 merge 方法相当,但由于代码更分散,可能导致可读性稍差。

适用场景

  • map.merge(num, 1, Integer::sum);

    • 适用于需要合并操作且对代码简洁性和原子性有要求的场景,尤其是在并发环境中。
    • 适用于更复杂的合并操作,如合并两个集合、列表或自定义的合并逻辑,只需要修改合并函数即可。
  • map.put(num, map.getOrDefault(num, 0) + 1);

    • 适用于简单的更新计数或递增操作,当不考虑并发问题时,使用 put 方法也比较方便。

总的来说,map.merge(num, 1, Integer::sum); 更适合处理合并和更新操作,特别是在多线程环境下,而 map.put(num, map.getOrDefault(num, 0) + 1); 更适合简单的递增计数操作,在单线程环境中使用。

posted @ 2025-01-17 21:07  借我杀死庸碌的情怀  阅读(243)  评论(0)    收藏  举报