为什么这个 Java 使用 HashMap 的代码会导致 NullPointerException?

Why does this Java code using HashMap cause NullPointerException?

这是我在解决leetcode问题时遇到的954. Array of Doubled Pairs

这是一张全局地图,其中存储了每个值的计数。我在下面使用这个函数来检查列表中的值(也在地图中)是否都是成对的(如果地图有 valuevalue * 2)。

    Map<Integer, Integer> map;
    
    private boolean isPaired( List<Integer> list) {
         for(int key : list) {
            if (map.containsKey(key)) {
                if (map.containsKey(key * 2)) {
                    updateMap(key);
                    updateMap(key * 2);
                } else {
                    return false;
                }
            }
        }
        return true;
    }
    
    private void updateMap(int key) {
        int value = map.get(key);
        if (value - 1 == 0) {
            map.remove(key); 
        } else {
            map.put(key , value - 1); 
        }
    }

对于这种情况(9945 0、10052 1 和 10003 2),它抛出 NullPointerException。这是异常消息:

java.lang.NullPointerException
  at line 54, Solution.updateMap
  at line 44, Solution.isPaired
  at line 26, Solution.canReorderDoubled
  at line 54, __DriverSolution__.__helper__
  at line 84, __Driver__.main

当我将函数 isPaired 更改为以下代码时:

 private boolean isPaired(List<Integer> list) {
         for(int key : list) {
            if (map.containsKey(key)) {
                updateMap(key);
                if (map.containsKey(key * 2)) {
                    updateMap(key * 2);
                } else {
                    return false;
                }
            }
        }
        return true;
    }

NullPointerException 不再发生。 为什么会发生这些?

map.get()可以returnnull(如果找不到key)

如果您尝试将 null 分配给基本类型 int 的变量,您将得到 NullPointerException(另请参阅 Unboxing Null-Object to primitive type results in NullPointerException, fine?)。

因此,如果您不通过 map.containsKey(key) 检查该值是否存在或在将其转换为 int 之前检查 null 的结果,则会出现异常。

正如在 中正确提到的那样,您的修改版本会在第一次修改后检查是否存在第二个键,即使两个键的值相同([= 的情况也是如此) 18=]) 并且第一次修改删除了第二次修改查找的密钥。

您的地图只能包含具有整数类型键的整数类型对象。

Map<Integer, Integer> map = new HashMap<>();

当地图不包含特定键的对象时,它将 return 为空。

map.get(key); --> will return a null-Integer

当您尝试将 Integer-Object 拆箱为 int 值时,当 Integer-Object 为 null 时,这将抛出 NullPointerException。

int value = map.get(key); // throws NullPointerException

让我们在 jshell 中试试这个。所以打开一个控制台-window 并使用 jshell:

启动 JShell

第一种情况会出现NullPointerException (NPE),因为keykey*2key=0时是相同的值。第二个版本的代码在第一个映射已被删除后测试 key*2 是否存在,因此它不会遇到 NPE。