ValueOf()有时会产生 NullPointerException

我有这个密码:

package tests;


import java.util.Hashtable;


public class Tests {


public static void main(String[] args) {


Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();


System.out.println("TEST 1");
System.out.println(modifiedItems.get("item1")); // Prints null
System.out.println("TEST 2");
System.out.println(modifiedItems.get("item1") == null); // Prints true
System.out.println("TEST 3");
System.out.println(Boolean.valueOf(null)); // Prints false
System.out.println("TEST 4");
System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
System.out.println("FINISHED!"); // Never executed
}
}

我的问题是,我不明白为什么 测试3工作得很好(它打印 false而不产生 NullPointerException) ,而 测试4抛出一个 NullPointerException。正如您在测试 12中看到的,nullmodifiedItems.get("item1")等于 null

Java7和 Java8中的行为是相同的。

13361 次浏览

由于 modifiedItems.get返回 Boolean(没有可浇注到 String) ,因此将使用的签名是 Boolean.valueOf(boolean),其中 Boolean被外包给原始 boolean。一旦 null返回到那里,使用 NullPointerException就会失败。

你必须仔细观察哪些过载被调用:

  • Boolean.valueOf(null) is invoking Boolean.valueOf(String). This doesn't throw an NPE even if supplied with a null parameter.
  • Boolean.valueOf(modifiedItems.get("item1"))正在调用 Boolean.valueOf(boolean),因为 modifiedItems的值是 Boolean类型的,这需要进行拆箱转换。因为 modifiedItems.get("item1")null,所以正是解除该值的装箱(而不是 Boolean.valueOf(...))引发 NPE。

确定调用哪个重载的规则是 毛茸茸的,但它们大致是这样的:

  • 在第一次传递中,搜索方法匹配时不允许装箱/解箱(也不允许变量的方法)。

    • Because null is an acceptable value for a String but not boolean, Boolean.valueOf(null) is matched to Boolean.valueOf(String) in this pass;
    • Boolean对于 Boolean.valueOf(String)或者 Boolean.valueOf(boolean)都是不可接受的,所以在这个过程中 Boolean.valueOf(modifiedItems.get("item1"))没有匹配的方法。
  • In a second pass, a method match is searched for, allowing boxing/unboxing (but still not variable arity methods).

    • Boolean可以解除装箱到 boolean,因此在这个步骤中 Boolean.valueOf(boolean)Boolean.valueOf(modifiedItems.get("item1"))匹配; 但是编译器必须插入解除装箱转换来调用它: Boolean.valueOf(modifiedItems.get("item1").booleanValue())
  • (还有第三个通道,允许使用可变的属性方法,但是这里没有关系,因为前两个通道与这些情况相匹配)

方法签名

方法 Boolean.valueOf(...)有两个签名:

  1. public static Boolean valueOf(boolean b)
  2. public static Boolean valueOf(String s)

您的 modifiedItems值是 Boolean。您不能将 Boolean强制转换为 String,因此将选择第一个签名

布尔展开

在你的口供里

Boolean.valueOf(modifiedItems.get("item1"))

可以理解为

Boolean.valueOf(modifiedItems.get("item1").booleanValue())

但是,modifiedItems.get("item1")返回 null,所以你基本上有

null.booleanValue()

显然是 NullPointerException

正如安迪已经很好地描述了 NullPointerException的原因:

这是由于布尔反装箱:

Boolean.valueOf(modifiedItems.get("item1"))

转换成:

Boolean.valueOf(modifiedItems.get("item1").booleanValue())

如果 modifiedItems.get("item1")为空,则抛出 NullPointerException

Now I would like to add one more point here that un-boxing of the following classes to their respective primitives can also produce NullPointerException exception if their corresponding returned objects are null.

  1. 字节-字节
  2. 字符-字符
  3. 漂浮-漂浮
  4. Int-Integer
  5. long - Long
  6. 短-短
  7. 双倍,双倍

密码如下:

    Hashtable<String, Boolean> modifiedItems1 = new Hashtable<String, Boolean>();
System.out.println(Boolean.valueOf(modifiedItems1.get("item1")));//Exception in thread "main" java.lang.NullPointerException


Hashtable<String, Byte> modifiedItems2 = new Hashtable<String, Byte>();
System.out.println(Byte.valueOf(modifiedItems2.get("item1")));//Exception in thread "main" java.lang.NullPointerException


Hashtable<String, Character> modifiedItems3 = new Hashtable<String, Character>();
System.out.println(Character.valueOf(modifiedItems3.get("item1")));//Exception in thread "main" java.lang.NullPointerException


Hashtable<String, Float> modifiedItems4 = new Hashtable<String, Float>();
System.out.println(Float.valueOf(modifiedItems4.get("item1")));//Exception in thread "main" java.lang.NullPointerException


Hashtable<String, Integer> modifiedItems5 = new Hashtable<String, Integer>();
System.out.println(Integer.valueOf(modifiedItems5.get("item1")));//Exception in thread "main" java.lang.NullPointerException


Hashtable<String, Long> modifiedItems6 = new Hashtable<String, Long>();
System.out.println(Long.valueOf(modifiedItems6.get("item1")));//Exception in thread "main" java.lang.NullPointerException


Hashtable<String, Short> modifiedItems7 = new Hashtable<String, Short>();
System.out.println(Short.valueOf(modifiedItems7.get("item1")));//Exception in thread "main" java.lang.NullPointerException


Hashtable<String, Double> modifiedItems8 = new Hashtable<String, Double>();
System.out.println(Double.valueOf(modifiedItems8.get("item1")));//Exception in thread "main" java.lang.NullPointerException

理解它的一种方法是,当调用 Boolean.valueOf(null)时,正确地告诉 java 计算 null。

然而,当调用 Boolean.valueOf(modifiedItems.get("item1"))时,Java 被告知从对象类型 Boolean 的 HashTable 中获取一个值,但是它没有找到类型 Boolean,而是找到了一个死胡同(null) ,即使它期望的是 Boolean。抛出 NullPointerException 异常是因为 Java 的这一部分的创建者认为这种情况是程序出错的实例,需要程序员的注意。(有些意外发生了。)

In this case it is more the difference between deliberately declaring that you intended the null to be there, and java finding a missing reference to an object (null) where an object was intended to be found.

有关 NullPointerException 的更多信息,请参见下面的答案: Https://stackoverflow.com/a/25721181/4425643