Можно ли сгенерировать исключение NullPointerException программно? - PullRequest
43 голосов
/ 24 июля 2010

Когда существует постусловие, это возвращаемое значение метода не должно быть нулевым, что можно сделать?

Я мог бы сделать

assert returnValue != null : "Not acceptable null value";

, но утверждения можно было отключить!

Так можно ли сделать

if(returnValue==null)
      {
           throw new NullPointerException("return value is null at method AAA");
      }

?

Или лучше использовать пользовательское исключение (например, NullReturnValueException) для такого условия?

Ответы [ 19 ]

61 голосов
/ 24 июля 2010

Я бы порекомендовал вам никогда не бросать NullPointerException самостоятельно.

Основная причина не делать этого, как сказал Турбьёрн Равн Андерсен в комментарии ниже, заключается в том, что вы не хотите смешивать «настоящие, плохие NPE» с намеренно выброшенными NPE.

Итак, пока вы не уверены, что способны распознать «действительный» NPE, я бы рекомендовал использовать IllegalArgumentException, если вы хотите сообщить своему API-пользователю, что null не является допустимым значением аргумента.Поведение вашего метода при передаче недопустимых нулевых параметров должно быть задокументировано.

Другой (более современный imho) вариант - использовать @NotNull аннотацию рядом с аргументом.Вот статья об использовании аннотации @NotNull .

Как я упоминал ранее, также могут быть случаи, когда бросание NPE не будет смущать ни вас, ни ваших товарищей по команде: причина NPEдолжно быть четким и узнаваемым.

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

checkNotNull(arg, msg) выбрасывает NPE, но из трассировки стека совершенно ясно, что он был создан Preconditions.checkNotNull() и, таким образом, это не неизвестная ошибка, а скорее ожидаемое поведение.

41 голосов
/ 25 июля 2010

Я не вижу проблем с тем, чтобы бросить NPE как можно раньше, прежде чем JVM сделает это за вас - в частности, для нулевых аргументов.Кажется, есть некоторые споры об этом, но есть много примеров в библиотеках Java SE, которые делают именно это.Я не понимаю, почему NPE должен быть святым в том смысле, что вы не можете бросить его сами.

Однако я отвлекся.Этот вопрос о чем-то другом.Вы говорите о постусловии, утверждающем, что возвращаемое значение не должно быть нулевым.Конечно, нулевое значение в этом случае означало бы, что у вас есть ошибка внутри самого метода ?

Как бы вы это зафиксировали?«Этот метод генерирует исключение NullPointerException, если возвращаемое значение неожиданно равно нулю»?Не объясняя, как это могло произойти?Нет, я бы использовал здесь утверждение.Исключения следует использовать для ошибок, которые могут предположительно произойти, - чтобы не охватывать вещи, которые могут произойти, если в методе что-то не так, потому что это никому не поможет.

27 голосов
/ 24 июля 2010

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

Утверждения хороши для отладки, но не хороши, если вам нужнообрабатывать определенные условия, так что это не очень хороший способ справиться с ошибкой.

12 голосов
/ 22 марта 2013

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

Исходя из моего опыта, Java-программисты очень быстро узнают, что это исключение вызвано ошибкой в ​​коде, поэтому выбрасывание этого вручную будет крайне запутанным для большинства из них. IllegalArgumentException - лучшая идея, когда вы передаете недопустимый аргумент (например, ноль, где что-то не должно быть нулевым).

Это также вызывает другую эвристику. NPE = здесь кто-то допустил ошибку в коде, IllegalArgumentException = объект, данный методу, недопустим.

С другой стороны, Javadoc сообщает:

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

Так что бросать NPE было бы законно , однако это не обычная практика, поэтому я бы порекомендовал IllegalArgumentException.

7 голосов
/ 24 июля 2010

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

catch (NullPointerException npe) {
  if (npe.getMessage().equals("Null return value from getProdByCode") {
    drawToUser("Unable to find a product for the product type code you entered");
  } 
}

Это верный индикатор того, что вы делаете что-то не так.Поэтому, если нулевое возвращаемое значение является показателем состояния системы, с которым вы действительно можете общаться, используйте исключение, которое сообщает об этом состоянии.Не так много случаев, когда я могу придумать, где имеет смысл обнулить проверку ссылки, чтобы просто бросить нулевой указатель.Обычно следующая строка кода в любом случае забрасывает нулевой указатель (или что-то более информативное)!

5 голосов
/ 24 июля 2010

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

Если вы проверяете параметры вашего метода в самом начале, throw new IllegalArgumentException("foo==null") также приемлем для меня.

4 голосов
/ 22 марта 2013

http://pmd.sourceforge.net/pmd-5.0.1/rules/java/strictexception.html
"Избегайте выбрасывания исключений NullPointerException. Это сбивает с толку, поскольку большинство людей предполагает, что виртуальная машина их выбросила. Попробуйте вместо этого использовать IllegalArgumentException; это будет ясно рассматриваться как исключение, инициированное программистом."

3 голосов
/ 24 июля 2010

JavaDoc для NullPointerException состояния:

Брошенный, когда приложение пытается использовать ноль в случае, когда объект требуется. К ним относятся:

* Calling the instance method of a null object.
* Accessing or modifying the field of a null object.
* Taking the length of null as if it were an array.
* Accessing or modifying the slots of null as if it were an array.
* Throwing null as if it were a Throwable value. 

Приложения должны генерировать экземпляры этот класс для обозначения других незаконных использование нулевого объекта.

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

Если, напротив, вы считаете, что условие post может быть нарушено, возможно, было бы неплохо включить больше отладочной информации, такой как аргументы, с которыми был вызван метод.

3 голосов
/ 24 июля 2010

Если вы описываете метод контракта, где возвращаемое значение не может быть null, тогда вам лучше убедиться, что вы не вернете null.Но это вовсе не исключение NullPointerException.Если возвращаемое значение равно null, то, очевидно, вызывающий абонент либо дал вам неверные аргументы ( IllegalArgumentException ), либо вы не в допустимом состоянии ( IllegalStateException ), либопроизошло другое, гораздо более значимое исключительное условие, кроме NullPointerException (которое обычно указывает на ошибку программирования).

1 голос
/ 24 июля 2010

Часто очень хорошая идея бросить NPE до того, как логика станет настолько глубокой, что вызывающему программисту будет трудно понять, что же является нулевым. Методы addListener () являются хорошим примером.

Несмотря на то, что в JDK есть неинформированные отрицательные голоса, в JDK есть много методов, которые делают именно это.

...