当运行这个。
public class WhatTheShoot {
public static void main(String args[]){
try {
throw null;
} catch (Exception e){
System.out.println(e instanceof NullPointerException);
System.out.println(e instanceof FileNotFoundException);
}
}
}
响应是:
true
false
这对我来说是相当惊人的。我本以为这将是一个编译时错误。
为什么我可以在Java中抛出null,为什么它要把它上传到NullPointerException?
(其实我也不知道这是不是 "upcast",因为我扔的是null)
除了一个非常愚蠢的面试问题(请不要在面试中问这个问题),我看不出有任何理由来 throw null
. 也许你想被解雇,但那是... ... 我是说,为什么还有人 throw null
?
趣事 IntelliJ IDEA 12告诉我,我的行。e instanceof NullPointerException
,永远是假的。这根本就不是真的。
看起来好像不是那么回事 null
被视为 NullPointerException
但是,尝试的行为 throw null
本身 抛出 NullPointerException
换句话说: throw
检查其参数是否为非空,如果为空,则抛出一个 NullPointerException
.
JLS 14.18 规定了 这种行为。
如果Expression的评估正常完成,产生一个空值,那么就会创建一个NullPointerException类的实例V',并抛出,而不是空值。然后抛出语句突然完成,原因是抛出了一个值为V'的实例。
为什么会上传到NullPointerException呢?
按照 JLS 14.18:
throw语句首先对Expression进行评估,如果Expression的评估因为某种原因突然完成,那么throw就会因为这个原因突然完成。如果Expression的评估由于某种原因突然完成,那么throw语句就会因为这个原因而突然完成,如果Expression的评估正常完成,产生一个非空值V,那么throw语句就会突然完成,原因是抛出了一个空值。如果Expression的评估正常完成,产生了一个非空值V,那么throw语句突然完成,原因是抛出了一个值V。如果Expression的评估正常完成,产生一个空值,那么就会创建一个类NullPointerException的实例V',并代替空值抛出。 抛出语句就会突然完成,原因是抛出了一个带值V'的抛出。
为什么我可以在java中抛出null?
你可以抛出类型为 Throwable
而既然 null
的有效参考。Throwable
,编译器允许它。
这就是 Neal Gafter说 (归档)
尽管null可以分配给每一个引用类型,但null的类型本身并不是一个引用类型。我们的本意是要在JLS第三版中删除关于抛出语句中的表达式是引用类型的要求,但这一改动实际上从未在发布的版本中实现。因此,这是一个我在 SE 5 中引入的 javac 编译器 bug。
它的行为符合 JLS:
如果Expression的评估正常完成,产生一个null值,那么就会创建一个NullPointerException类的实例V'并抛出,而不是null。
这样一想,就知道为什么会这样了。
try {
Exception foo = null;
if(false) {
foo = new FileNotFoundException();
} // Oops, forgot to set foo for the true case..
throw foo;
} catch (Exception e){
System.out.println(e instanceof NullPointerException);
System.out.println(e instanceof FileNotFoundException);
}
我不太清楚,但我猜测 "throw null"; 确实是 不 工作,而尝试它将导致程序抛出一个异常,而这个异常恰好是(击鼓传花)NullPointerException...。
null 可以投射成任何东西*,包括一个Exception。就像如果你的方法签名指定你应该返回一个Exception(或者确实是一个字符串,或者Person类),你可以返回null一样,你也可以抛出它。
*不包括基元类型。
bharal......这看起来是javac编译器的bug。我认为它是在SE 5.Null可以分配给任何引用类型中引入的。但是,"null的类型 "本身并不是一个引用类型。程序编译时,因为null可以简单地投向Exception。此外,throw在声明之后寻找对象引用,由于null可以作为对象引用使用,所以会显示结果。
JLS文档中关于throw的描述是
"一个 throw 语句首先评估 Expression。如果Expression的评估因为某种原因而突然完成,那么throw就会因为这个原因而突然完成。如果Expression的评估正常完成,产生了一个非空值V,那么throw语句突然完成,原因是抛出了一个值为V的抛物。如果Expression的评估正常完成,产生了一个空值,那么就创建了一个类NullPointerException的实例V',并抛出了空值。抛出语句就会突然完成,原因是抛出了一个带值V'。"