Должен ли я генерировать NullPointerException явно или позволить Java сделать это для меня? - PullRequest
11 голосов
/ 17 октября 2011

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

  1. проверьте возвращаемое значение для null и создайте исключение NullPointerException самостоятельно, либо
  2. Должен ли я просто позволить 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 (что я и написал изначально во фрейдовском листке), когда он не может найти его, но вместо этого возвращает ноль. Я думаю, что выбрасывать исключение NullPointerException - это правильно, потому что это указывает на фактическую ошибку в развертывании программного обеспечения.

Ответы [ 6 ]

8 голосов
/ 17 октября 2011

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

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

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

8 голосов
/ 17 октября 2011

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

2 голосов
/ 17 октября 2011

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

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

Вы получите:

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

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

  • и NullPointerException и IllegalStateException расширяет RuntimeException , поэтому вы не вносите существенных изменений в вашу программу

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

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

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

1 голос
/ 17 января 2012

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

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 (например, NullArgumentException ) Apache Commons Math, либо старые исключения, найденные в Apache Common Lang 2.x . Это моя позиция для NPE и исключений типа IllegalArgument. Я не обязательно согласен с позицией Apache Common Lang о предпочтении использовать стандартные исключения JDK над более семантически значимыми исключениями. Но это только я, и я схожу с касательной ...

... так что вернемся к первоначальному вопросу. Как я уже говорил ранее, бросать NPE, как это, можно быстро и грязно (когда вы находитесь в одном из тех «нужно вытащить этот хрен !! (10 + 1)» вида ситуаций.

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

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

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

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

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

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

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

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

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

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

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

0 голосов
/ 16 августа 2013

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

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

0 голосов
/ 17 октября 2011

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

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

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

...