为什么在Java中可以抛出null?[重复]

问题描述 投票:312回答:7

当运行这个。

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,永远是假的。这根本就不是真的。

java exception-handling nullpointerexception
7个回答
418
投票

看起来好像不是那么回事 null 被视为 NullPointerException但是,尝试的行为 throw null 本身 抛出 NullPointerException

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

JLS 14.18 规定了 这种行为。

如果Expression的评估正常完成,产生一个空值,那么就会创建一个NullPointerException类的实例V',并抛出,而不是空值。然后抛出语句突然完成,原因是抛出了一个值为V'的实例。


97
投票

为什么会上传到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。


21
投票

它的行为符合 JLS:

如果Expression的评估正常完成,产生一个null值,那么就会创建一个NullPointerException类的实例V'并抛出,而不是null。


17
投票

这样一想,就知道为什么会这样了。

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);
}

13
投票

我不太清楚,但我猜测 "throw null"; 确实是 工作,而尝试它将导致程序抛出一个异常,而这个异常恰好是(击鼓传花)NullPointerException...。


-3
投票

null 可以投射成任何东西*,包括一个Exception。就像如果你的方法签名指定你应该返回一个Exception(或者确实是一个字符串,或者Person类),你可以返回null一样,你也可以抛出它。

*不包括基元类型。


-3
投票

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'。"

© www.soinside.com 2019 - 2024. All rights reserved.