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

运行这个时候:

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的行为本身抛出一个NullPointerExceptionexception。

换句话说, throw检查它的参数是否为空,如果是null,则抛出一个NullPointerExceptionexception。

JLS 14.18 指定了这个行为:

如果对Expression的评估正常完成,则生成一个空值,然后创build类NullPointerException的实例V'并抛出而不是null。 throw语句突然完成,原因是一个值为V'的throw。

为什么它向上抛出NullPointerException?

根据JLS 14.18 :

一个throw语句首先评估expression式。 如果由于某种原因,expression式的评估突然完成,那么抛出就会因为这个原因而突然完成。 如果Expression的求值正常完成,产生一个非空值V,则throw语句突然完成,原因是一个带有值V的throw。 如果对Expression的求正常完成,产生一个空值,那么一个实例V'类NullPointerException的创build和抛出而不是null。 throw语句突然完成,原因是一个值为V'的throw。

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

您可以抛出Throwabletypes的对象,由于nullThrowable的有效引用,编译器允许它。

这就是Neal Gafter所说的

虽然null可分配给每个引用types,但nulltypes本身不是引用types。 我们的意图是,将throw语句中的expression式作为引用types的要求将从JLS的第三版中删除,但是这种更改实际上并没有真正将其引入到已发布的版本中。 因此,这是我在SE 5中介绍的一个javac编译器错误。

它的行为符合JLS :

如果对Expression的评估正常完成,则生成一个空值,然后创build类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); } 

不知道肯定,但我猜测“扔零”; 不起作用,并尝试它导致程序抛出一个exception,并且该例外碰巧是(鼓滚)NullPointerException …

null可以转换为任何*,包括一个Exception。 就像你可以返回null如果你的方法签名指定你应该返回一个Exception(或者确实是一个string,或Person类),你可以抛出它。

*不包括原始types。

bharal …它看起来是一个javac编译器错误。 我认为它是在SE 5中引入的。空值可以被分配给任何引用types。 但是,“null的types”本身不是一个引用types。 该程序编译它,因为null可以简单地投入到exception。 此外,在声明之后抛出对象引用,因为null可以作为对象引用来显示结果。

JLS文档关于抛出:

“一个throw语句首先评估expression式。 如果由于某种原因,expression式的评估突然完成,那么抛出就会因为这个原因而突然完成。 如果expression式的求值正常完成,产生一个非空值V,则throw语句突然完成,原因是一个带有值V的抛出。如果expression式的求值正常完成,产生一个空值,那么一个实例V'类NullPointerException的创build和抛出而不是null。 throw语句突然完成,原因是一个值为V'的抛出。