考虑以下代码
public class JDK10Test {
public static void main(String[] args) {
Double d = false ? 1.0 : new HashMap<String, Double>().get("1");
System.out.println(d);
}
}
在JDK8上运行时,此代码将打印null
,而在JDK10上,此代码将输出NullPointerException
Exception in thread "main" java.lang.NullPointerException
at JDK10Test.main(JDK10Test.java:5)
除了JDK10编译器生成的两条额外的指令之外,编译器生成的字节码几乎是相同的,这两条指令与自动装箱相关,似乎是造成NPE的原因。
15: invokevirtual #7 // Method java/lang/Double.doubleValue:()D
18: invokestatic #8 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
这种行为是JDK10中的错误,还是为了使行为更严格而有意做出的改变?
JDK8: java version "1.8.0_172"
JDK10: java version "10.0.1" 2018-04-17
发布于 2018-06-09 09:09:49
JLS10似乎没有指定对条件运算符的任何更改,但我有一个理论。
根据JLS8和JLS10,如果第二个表达式(1.0
)的类型为double
,第三个表达式(new HashMap<String, Double>().get("1")
)的类型为Double
,则条件表达式的结果为double
类型。Java8中的JVM似乎足够聪明,因为您将返回一个Double
,所以没有理由首先将HashMap#get
的结果解包为double
,然后再将其装箱回Double
(因为您指定了Double
)。
为了证明这一点,在您的示例中将Double
更改为double
,然后抛出一个NullPointerException
(在JDK8中);这是因为现在正在进行拆箱,而null.doubleValue()
显然抛出了一个NullPointerException
。
double d = false ? 1.0 : new HashMap<String, Double>().get("1");
System.out.println(d); // Throws a NullPointerException
这似乎在10年中发生了变化,但我不能告诉你为什么。
https://stackoverflow.com/questions/50769880
复制相似问题