关于异常处理:为什么我可以在Java中抛出null?

Why can I throw null in Java?

本问题已经有最佳答案,请猛点这里访问。

运行时:

1
2
3
4
5
6
7
8
9
10
11
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);
        }
    }
}

回应是:

1
2
true  
false

这对我来说相当惊人。 我原本以为这会造成编译时错误。

为什么我可以在Java中抛出null,为什么要将它转换为NullPointerException呢?

(实际上,我不知道它是否是"向上",因为我扔的是null)

除了一个非常愚蠢的面试问题(请不要在面试中问这个)我看不出throw null的任何理由。 也许你想被解雇,但那是......我的意思是,为什么其他人throw null呢?

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


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

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

JLS 14.18指定了这种行为:

If evaluation of the Expression completes normally, producing a null value, then an instance V' of class NullPointerException is created and thrown instead of null. The throw statement then completes abruptly, the reason being a throw with value V'.


为什么它会将它转发为NullPointerException?

根据JLS 14.18:

A throw statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the throw completes abruptly for that reason. If evaluation of the Expression completes normally, producing a non- null value V, then the throw statement completes abruptly, the reason being a throw with value V. If evaluation of the Expression completes normally, producing a null value, then an instance V’ of class NullPointerException is created and thrown instead of null. The throw statement then completes abruptly, the reason being a throw with value V’.

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

您可以抛出Throwable类型的对象,因为nullThrowable的有效引用,编译器允许它。

这就是Neal Gafter所说的

尽管null可分配给每个引用类型,但null的类型本身不是引用类型。我们的意图是要求将throw语句中的表达式作为引用类型从JLS的第三版中删除,但该更改实际上从未实际进入已发布的版本。因此,这是我在SE 5中介绍的javac编译器错误。


它的行为符合JLS:

If evaluation of the Expression completes normally, producing a null value, then an instance V' of class NullPointerException is created and thrown instead of null.


以这种方式思考它会使其更加明显:

1
2
3
4
5
6
7
8
9
10
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);
}

不确定,但我猜"扔掉";不起作用,并尝试它会导致程序抛出异常,并且该异常恰好是(鼓滚动)NullPointerException ...


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

*不包括原始类型。


bharal ...它看起来像一个javac编译器bug。我认为它是在SE 5中引入的。
Null可以分配给任何引用类型。但是,"null类型"本身不是引用类型。程序编译它,因为null可以简单地转换为Exception。
此外,throw会在声明后查找对象引用,并且null可以作为对象引用,它会显示结果。

关于throw的JLS文档:

"A throw statement first evaluates the Expression. If the evaluation
of the Expression completes abruptly for some reason, then the throw
completes abruptly for that reason. If evaluation of the Expression
completes normally, producing a non-null value V, then the throw
statement completes abruptly, the reason being a throw with value V.
If evaluation of the Expression completes normally, producing a null
value, then an instance V’ of class NullPointerException is created
and thrown instead of null. The throw statement then completes
abruptly, the reason being a throw with value V’."