Почему я могу выбросить нуль в 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?

(На самом деле, я не знаю, является ли это "upcast", учитывая, что я бросаю нуль)

Помимо действительно действительно глупых вопросов интервью (пожалуйста, никто не спрашивает об этом в интервью), я не вижу причин для throw null. Может быть, вы хотите уволить, но это... Я имею в виду, почему еще кто-нибудь throw null?

Фантастический факт IntelliJ IDEA 12 говорит мне, что моя строка e instanceof NullPointerException всегда будет ложной. Это совсем не так.

Ответ 1

Похоже, что null рассматривается как NullPointerException, но действие попытки throw null само выбрасывает NullPointerException.

Другими словами, throw проверяет, что его аргумент является ненулевым, а если он равен нулю, он выдает NullPointerException.

JLS 14.18 указывает такое поведение:

Если оценка Expression завершается нормально, создавая нулевое значение, тогда создается экземпляр V 'класса NullPointerException и выбрасывается вместо null. Затем оператор throw завершается внезапно, причиной является бросок со значением V '.

Ответ 2

, почему он преобразует его в исключение NullPointerException?

По JLS 14.18:

Оператор throw сначала оценивает выражение. Если по какой-либо причине оценка Expression неожиданно завершается, то по этой причине бросок завершается внезапно. Если оценка Expression завершается нормально, создавая ненулевое значение V, то инструкция throw завершается внезапно, поэтому причиной является бросок со значением V. Если оценка Expression выполняется нормально, создавая нулевое значение, тогда экземпляр V класса NullPointerException создается и выбрасывается вместо нулевого. Задание throw завершается внезапно, причиной является бросок со значением V.

Почему я могу выбросить null в java?

Вы можете бросать объекты типа Throwable, и поскольку null является допустимой ссылкой для Throwable, компилятор разрешает это.

Вот что Нил Гафтер говорит

Хотя null присваивается каждому ссылочному типу, тип null не является ссылочным типом. Мы были намерены, что требование о том, чтобы выражение в выражении throw было ссылочным типом, должно было быть удалено из третьего издания JLS, но это изменение никогда не попало в опубликованную версию. Таким образом, это ошибка компилятора javac, которую я ввел в SE 5.

Ответ 3

Он ведет себя в соответствии с JLS:

Если оценка Expression завершается нормально, создавая нулевое значение, тогда создается экземпляр V 'класса NullPointerException и выбрасывается вместо null.

Ответ 4

Размышление об этом таким образом делает более очевидным, почему это работает:

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

Ответ 5

Не знаю точно, но я предполагаю, что "throw null"; не работает, и попытка его заставляет программу генерировать исключение, и это исключение случается (барабанное рулон) NullPointerException...

Ответ 6

bharal... Он выглядит ошибкой компилятора javac. Я думаю, что это было введено в SE 5. Null может быть присвоен любому ссылочному типу. Однако "тип null" сам по себе не является ссылочным типом. Программа скомпилирует его, потому что null может просто вставить в Exception. И, кроме того, бросок ищет ссылку на объект после объявления, а так как NULL может работать как ссылка на объект, он отображает результат.

Документ JLS о броске как:

"Сначала выражение throw выражает выражение. Если оценка из Выражения неожиданно завершается по какой-то причине, тогда бросок по этой причине завершается внезапно. Если оценка выражения нормально завершается, производя ненулевое значение V, тогда бросок утверждение завершается внезапно, причиной является бросок со значением V. Если оценка Expression завершается нормально, создавая нулевое значение value, тогда создается экземпляр V класса NullPointerException и выбрасывается вместо null. Затем выполняется инструкция throw внезапно, причиной является бросок со значением V."

Ответ 7

null может быть применено к чему-либо *, включая исключение. Так же, как вы можете вернуть null, если указана ваша сигнатура метода, вы должны вернуть исключение (или, действительно, строку или класс Person), вы можете его выбросить.

* Исключая примитивные типы.