Должен ли я явно бросать NullPointerException или позволить Java сделать это для меня?

Как гласит название, мне интересно, что лучше всего относится к бросанию NullPointerExceptions. В частности, если у меня есть внешняя библиотечная функция, которая может возвращать null в обстоятельствах, которые я не хочу обрабатывать (см. Ниже для конкретного примера), поскольку null указывает на проблему с программным обеспечением. Вопрос в том, должен ли я

  • проверить возвращаемое значение для null и выбросить NullPointerException самостоятельно, или
  • Должен ли я просто позволить Java выполнять грязную работу для меня, как только я попытаюсь использовать этот объект.

Первый подход позволяет мне добавить дополнительную информацию, так как я могу построить исключение NullPointerException, но второе делает для более чистого кода, на мой взгляд. Я также хотел бы задаться вопросом о любых последствиях для производительности, то есть является ли Java более эффективным при бросании NPE "изначально"?

В качестве примера я пытаюсь использовать Java Speech API для создания речевого синтезатора, используя следующий код:

synthesizer = Central.createSynthesizer(generalDesc);

if (synthesizer == null) {
    // (1) throw NPE explicitly
    throw new NullPointerException("No general domain synthesizer found.");
}

// (2) let the JVM throw the NPE when dereferencing
synthesizer.allocate();

Central.createSynthesizer возвращает null, если он не может найти подходящий синтезатор, который чаще всего вызван отсутствием файла speech.properties. Таким образом, это вопрос неправильной настройки системы и довольно неустранимый из во время выполнения, а не для ситуаций, которые необходимо обрабатывать программно. Таким образом, я считаю, что бросание NullPointerException является допустимым ответом, поскольку это указывает на ошибку (не в коде, а в развертывании программного обеспечения). Но поскольку объект synthesizer разыменован в самом следующем утверждении, должен ли я позволить JVM бросить NPE для меня и сохранить нулевую проверку?

Добавление. Учитывая, что функция speech.properties загружается при запуске JVM в файловой системе (обычно) "user.home" или "java.home" /lib ", вызывает недоумение, что createSynthesizer не выставляет NPE (это то, что я написал изначально во фрейдистском слайде), когда он не находит его, но вместо него возвращает null. Я думаю, что бросать NullPointerException - это то, что нужно сделать здесь, потому что это указывает на реальную ошибку при развертывании программного обеспечения.

Ответ 1

В вашем случае: нет. Проверьте null и введите более значимое исключение, а не NPE.

В общем случае - если NPE не должен возникать, не проверяйте его явно, Java сделает это за вас. Меньше тестов для написания, меньше кода для чтения, меньше сложности для анализа.

Однако, если null ожидается как можно скорее, и интерпретировать соответствующим образом. В противном случае NullPointerException произойдет где-то позже в другой строке/методе, затрудняя отладку реальной проблемы.

Ответ 2

Я бы сказал, что вы никогда не должны явно создавать NullPointerException и вместо этого использовать тип исключения, который более четко описывает ситуацию. В вашем случае я бы сказал, что IllegalStateException соответствует ситуации "неправильной настройке системы и довольно неустранимой из во время выполнения". Или вы можете создать свой собственный ComponentMissingException. В случаях, когда требуемым параметром метода является null, обычно используется IllegalArgumentException.

Ответ 3

Я не хочу, чтобы null был действительным возвращаемым значением, даже в "исключительных обстоятельствах". Поэтому я беру еще один подход.

В вашем случае я бы аннотировал метод createSynthesizer (...) с @NotNull (@NotNull - примечание amazing). Вместо NPE я бы получил IllegalStateException, как только createSynthesizer (...) захочет вернуть null.

Вы получите:

java.lang.IllegalStateException: @NotNull method .../.../createSynthetiser(...) must not return null

Существует несколько преимуществ такого подхода:

  • как NullPointerException, так и IllegalStateException расширяет RuntimeException, поэтому вы принципиально не изменяете свою программу

  • исключение должно быть выбрано немедленно, где происходит ошибка (не позже, когда вы либо проверяете/бросаете себя, либо когда пытаетесь разыменовать нуль)

  • вам больше не нужно писать, если... == null/throw part.

В качестве гигантского дополнительного преимущества некоторые IDE (например, IntelliJ IDEA) будут предупреждать вас в реальном времени о возможных нарушениях @NotNull.

Ответ 4

Относительно исходного кода:

synthesizer = Central.createSynthesizer(generalDesc);

if (synthesizer == null) {
    // (1) throw NPE explicitly
    throw new NullPointerException("No general domain synthesizer found.");
}

// (2) let the JVM throw the NPE when dereferencing
synthesizer.allocate();

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

При идеальных обстоятельствах, я предпочитаю использовать исключения, относящиеся к неверным конфигурациям. И когда они недоступны, либо использовать подклассы NPE (например, Apache Commons Math NullArgumentException), либо старые исключения, найденные в Apache Common Lang 2.x. Это моя позиция в отношении исключений NPE и исключений типа IllegalArgument. Я не обязательно соглашаюсь с Apache Common Lang position, предпочитая использовать стандартные исключения JDK над более семантически значимыми исключениями. Но это только я, и я ухожу от касательной...

... так что вернемся к исходному вопросу. Как я уже говорил, бросая NPE, как будто, это нормально и грязно (когда вы в одном из них "нужно получить это sh1t out!! (10 + 1)". >

Обратите внимание, что это NPE, вызванный проблемой конфигурации приложения или системы, как вы ее правильно идентифицировали. То есть NPE не является основной причиной, симптомом или эффектом другого условия ошибки (в данном случае, ошибки конфигурации или среды).

Central.createSynthesizer возвращает null, если он не может найти подходящий синтезатор, который чаще всего вызван отсутствием речи. файл. Так что это вопрос неправильной настройки системы, и довольно не подлежащие восстановлению во время выполнения, а не обстоятельства, которые обрабатываться программно.

Невосстановимость - это не определенность. Приложение может иметь другие способы обработки этой ситуации программно.

Таким образом, я считаю, что NullPointerException - действительный ответ, поскольку он указывает на ошибку (не в коде, а в развертывании программного обеспечения). Но поскольку объект синтезатора разыменован в самом следующем утверждении, должен Я просто позволяю JVM бросать NPE для меня и сохранять нулевую проверку?

Я бы этого не сделал, даже при обстоятельствах, связанных с этими обстоятельствами. NPE, выброшенный этим путем JVM, будет иметь в нем очень неинформативное сообщение. В общем, проверьте все для NULL и бросьте описательное исключение (NPE или иначе), когда вы столкнетесь с ним.

Не проверяйте NPE, если вы можете гарантировать, что все, что вы получаете (параметры, например) уже были проверены для NPE уже (в зависимости от типа контракта).

Добавление: Учитывая, что речевые свойства загружаются, когда JVM должно существовать в файловой системе в (обычно) "user.home" или "java.home/lib", вызывает недоумение, что createSynthesizer не делает прямо бросайте NPE (это то, что я написал изначально в Freudian slip), когда он не находит его, но вместо этого возвращает null.

Опять же, это потому, что ответ на эту ситуацию специфичен для приложения. Приложение может решить перейти в режим хромирования с частичной функциональностью, а не сбой и сжигание на землю. Если createSynthesizer должен был выбросить NPE, тогда разработчик API заставит дизайнера приложения принять более позднюю версию или перейти на несколько большую длину, чтобы реализовать режим "хромирования" (при использовании catch/try вместо простой тест if-null.

Я думаю, что бросать исключение NullPointerException - это правильная вещь здесь, поскольку это указывает на реальную ошибку при развертывании программное обеспечение.

Опять же, только если NPE - это быстрое n-грязное решение, чтобы вытащить вещи из двери. В этих условиях это нормально. Лучшим подходом является определение того, что это такое, ошибка конфигурации.

Итак, было бы лучше иметь исключения для приложения, такие как IllegalConfigurationException или InvalidConfigurationException или IncompleteConfigurationException. Мне не нравится использовать java.lang.IllegalStateException для таких случаев, потому что это не вызвано вызовом чего-то в недопустимом состоянии. Недействительное состояние достигнуто из-за неправильной конфигурации. Возможно, я играю в семантические игры, но в таких случаях есть что-то нехорошее в использовании исключения IllegalStateException (что только я субъективен, я знаю.)

Ответ 5

Очень интересный вопрос.

Я думаю, что какой-то ProblemCreatingSynthesizerException должен быть брошен этим методом вместо того, чтобы возвращать null.

Я бы поставил нулевую проверку и выбросил NPE или другой пользовательский ProblemWithSynthesizerException свой собственный (Sun по какой-то причине задумал это исключение как исключение JVM-ish, не предназначенное для использования программистом. это то, что он говорит в некоторых учебных пособиях и книгах по сертификации. Однако я этого не покупаю, а некоторые часто бросаю свои собственные NPE в свои библиотеки).

Ответ 6

Я никогда не использовал Java, но если бы я использовал приложение, я бы хотел увидеть сообщение об ошибке, чем авария. NullPointerException звучит как ошибка в коде для меня - я бы предпочел увидеть сообщение об ошибке с инструкциями о том, как правильно настроить программу или, по крайней мере, гиперссылку на веб-страницу с такими указаниями.

Если бы я был пользователем и видел, что программа завершилась с NullPointerException, я бы подал ошибку против программы или, по крайней мере, смутился относительно того, что делать дальше.