为什么我可以抛出null在Java?

当运行这个:

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

这对我来说是相当惊人的。我本以为这会导致编译时错误。

为什么我可以抛出null在Java中,为什么它向上转换它到一个NullPointerException?

(实际上,我不知道它是否是一个“上置”,因为我抛出null)

除了一个非常非常愚蠢的面试问题(请不要在面试中问这个问题),我找不到任何理由throw null。也许你想被解雇,但那…我的意思是,否则为什么会有人throw null?

有趣的事实 IntelliJ IDEA 12告诉我,我的行,e instanceof NullPointerException,将永远是假的。这根本不是真的。

34807 次浏览

看起来并不是null被视为NullPointerException,而是试图throw null 本身的行为会抛出NullPointerException

换句话说,throw检查其参数是否为非空,如果为空,则抛出NullPointerException

指定此行为:

如果表达式的求值正常完成,产生空值,则创建NullPointerException类的实例V',并抛出而不是null。throw语句然后突然结束,原因是一个值为V'的throw。

我不确定,但我猜“throw null”;工作,并且尝试它会导致程序抛出一个异常,而该异常恰好是(drum roll) NullPointerException…

它的行为符合JLS:

如果表达式的求值正常完成,产生空值,则创建NullPointerException类的实例V',并抛出而不是null。

为什么要向上转换为NullPointerException?

根据JLS 14.18:

throw语句首先计算表达式的值。如果表达式的求值由于某种原因突然结束,则抛出操作也因此突然结束。如果表达式的求值正常结束,产生一个非空值V,则throw语句突然结束,原因是抛出值为V。

为什么我可以抛出null在java ?

你可以抛出类型为Throwable的对象,由于nullThrowable的有效引用,编译器允许这样做。

这就是尼尔·盖特说 (存档)

虽然null可以赋值给每个引用类型,但null类型本身并不是引用类型。我们的意图是从JLS的第三版中删除throw语句中的表达式是引用类型的要求,但这一更改实际上从未出现在发布版本中。因此,这是我在SE 5中介绍的javac编译器错误。

用这种方式思考可以更明显地解释为什么这样做是有效的:

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);
}
< p > bharal……它看起来是javac编译器错误。我认为它是在SE 5中引入的。 Null可以赋给任何引用类型。然而,“null类型”本身并不是引用类型。程序编译它,因为null可以简单地转换为Exception。 此外,throw在声明之后寻找对象引用,因为null可以作为对象引用,所以它显示结果

JLS文档中关于throw的描述如下:

throw语句首先计算表达式的值。如果评估 由于某种原因,表达式突然结束,然后抛出 因此突然完成。表达式的If求值 正常完成,产生一个非空值V,然后抛出 语句突然结束,原因是值为V的throw。 如果表达式的求值正常完成,则产生null 值,然后创建NullPointerException类的实例V ' 并抛出而不是null。然后throw语句完成 突然,原因是抛出值为V ' . "

可以被强制转换为任何类型*,包括异常。就像如果您的方法签名指定您应该返回一个Exception(或者实际上是一个字符串或Person类),您可以返回null一样,您可以抛出它。

*不包括基本类型。