Можно ли запрограммировать NullPointerException?

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

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

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

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

Так что нормально делать

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

?

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

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

Конечно, нет универсального закона против бросания 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");
  } 
}

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

Ответ 6

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

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

Ответ 7

JavaDoc для NullPointerException:

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

* 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. 

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

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

Книга, которую я назвал O'Reilly Java в Nutshell, которая написана экспертом, перечисляет это определение для NullPointerException:

Сигналы пытаются получить доступ к полю или вызвать метод нулевого объекта.

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

Ответ 11

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

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

Ответ 12

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

Ответ 13

В Java-стихе null всегда является допустимым значением при ожидании объекта. Лучше избегать таких невозможных условий сообщения. Если вы действительно не можете выполнить null, вам придется переработать свой метод, чтобы вы могли вернуть примитив.

Ответ 14

Абсолютно ДА.

Даже JDK7 разрешает это. См. Объекты # requireNonNull

void doWith(final Object mustBeNotNull) {

    /*
    // bush style
    if (mustBeNotNull == null) {
        throw new IllegalArgumentException("mustBeNotNull must not be null");
    }
    */

    /*
    // obama style
    if (mustBeNotNull == null) {
        throw new NullPointerException("mustBeNotNull must not be null");
    }
    */

    // kangnam style
    Objects.requireNonNull(mustBeNotNull, "mustBeNotNull must not be null");

    assert mustBeNotNull != null;
}

Ответ 15

Как однажды сказал Джошуа Блох: "Нуль сосет!":) всякий раз, когда есть пустое мое лицо, я пытаюсь использовать опцию, которую предоставляет guava. Преимущества для меня многочисленны.

Ответ 16

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

Постословие означает, что данный метод имеет ошибку, если условие не выполняется. Способ выразить это в коде - использовать assert для пост-состояния. Непосредственное бросание исключения, такого как NullPointerException или IllegalStateException, было бы немного ошибочным и, следовательно, ошибочным.

Можно ли запрограммировать NullPointerException?

Документ API Java API для NPE говорит "да", но, судя по голосам, указанным на этой странице, большинство разработчиков из 3: 1 говорит "нет". Поэтому я бы сказал, что это зависит от соглашений в вашей рабочей группе.

В документе API сначала перечисляются случаи, когда JVM создает NPE, потому что код пытается вызвать операцию на нулевой ссылке, которая требует какого-либо объекта (например, вызов метода или доступ к полю), а null - а не объект. Затем он указывает:

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

Интересно, что null называется "объектом" здесь, а это не так. Это напоминает мне, что само название NullPointerException является странным для языка, на котором нет указателей. (Вероятно, это было NullReferenceException, как в библиотеке классов Microsoft.NET.)

Итак, следует ли отклонить API-документ в этом счете? Я так не думаю. Библиотека классов использует NPE, как описано в документах, например, в java.nio.channels:

Если не указано иное, передача аргумента null конструктору или методу в любом классе или интерфейсе в этом пакете приведет к выбросу NullPointerException.

Это не NPE, созданный JVM, а закодированный NPE с прикрепленным сообщением об ошибке, в котором указан аргумент null (например, "in" is null!). (Код можно увидеть, выполнив javap -c -p java.nio.channels.Channels | more, ища private static void checkNotNull.) И есть много классов, которые используют NPE таким образом, по существу, как частный случай IllegalArgumentException.

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

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

Ответ 17

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

Проблема с Java-программистами и нулевым состоянием состоит в том, что люди происходят из фона C/С++, где NULL означает что-то много другое. В разыменовании C/С++ NULL (или дикий) указатель является серьезной проблемой, которая может вызвать проблемы с памятью или сбой вашей программы (очевидно, нежелательно). Если вы можете выйти из образа мышления C/С++, и вы понимаете, что у вас есть этот дополнительный слой, JVM, который обрабатывает это условие для вас, вы начинаете немного думать о NULL.

В С++ у нас есть ссылки, например, которые никогда не могут быть назначены NULL. В Java нет ссылок, но параметры объекта Java ведут себя скорее как указатели С++. Но на Java существует много ситуаций, в которых метод неявно НЕ должен получать нулевое значение для параметра! Итак, что мы делаем?

Проблема с обработкой null в Java, как и в С++, заключается в том, что это приводит к нулевым проверкам EVERYWHERE, тогда как в С++ вы просто объявляете метод для ссылки, в котором явно указано, что он не принимает NULL. Довольно скоро каждый метод должен иметь проверку на здравомыслие, чтобы просто подтвердить состояние программы в этой точке, создав беспорядок.

Это гораздо лучшее состояние ума для работы в предположении, что контракт по умолчанию по умолчанию заключается в том, что значение null недопустимо для значения параметра.

Почему? Хорошо, давайте посмотрим, что произойдет, когда такой метод получает значение null в качестве значения параметра. a) Возможно, это нормально, потому что это не разыгрывает ценность как часть ее поведения. В этом случае ничего не происходит. б) Значение разыменовывается. В этом случае поведение JVM - это именно то, что мы хотим: генерируется исключение, указывающее, что контракт метода был нарушен из-за того, что значение параметра равно null, и оно включает в себя трассировку стека, доводящую нас до line в методе, в котором значение используется таким образом.

Люди сталкиваются с проблемой NPE, потому что считают, что когда вы видите NPE в журналах, это означает "кто-то испортил". Но подумайте об этом на секунду. На самом деле разница в NPE как индикаторе fuckup в отличие от ожидаемого поведения? Я бы сказал, что основное отличие (и преимущество) использования NPE от ожидаемого поведения заключается в том, что он указывает не на метод, в котором он произошел, а на вызывающего за нарушение контракта метода. Это гораздо более полезная информация. Если бы мы просто проверяли значение null и генерировали другое исключение, мы могли бы оказаться под ложным впечатлением, что наблюдаемое поведение является ожидаемой ошибкой, когда действительно вызывающий нарушает контракт метода. Поздравляем, вы правильно предвосхитили, как вы, возможно, вызываете вызов метода, но все, что вы сделали, сбилось с пути в сторону того, что является реальной причиной исключения, или, в лучшем случае, вы используете два разных класса исключений чтобы показывать одно и то же и массово загрязнять код ненужным мусором. Тем не менее

Итак, когда дело доходит до этого, люди считают NPE табу. Буквально люди не позволят его бросить, потому что есть какое-то чувство стыда, которое происходит с ним, - как будто вы недостаточно умны, потому что вам не удалось догадаться, где значение будет null. Ну, я получил новости для вас, ребята, вы просто пишете более бесполезный код, чтобы сделать то же самое.

Некоторые примеры:

public void foo(Object o) {
  if (o == null) {
    throw new IGotchaException("HA! You're an IDIOT! I knew it!!");
  }
  o.bar();
}

public void foo(Object o) {
  o.bar();
}

^ Политически разные. Функционально, не так много.

public void foo(int a, long b, double c, Object o) {
  if (o == null) {
    throw new IllegalArgumentException("Oh. Uh. Well, you've passed me null here. I... I'm not sure where to go from here because this object is kind of required for this function to do what it supposed to do. Soooo... wouldja mind reworking your code a little bit so as to not pass null to this function as a parameter?! That'd be great thanks. Oh by the way, it cause we deference o 40 lines below here");
  }
  // ...
  o.doSomethingWithA(a);
}

public void foo(int a, long b, double c, Object o) {
  // ...
  o.doSomethingWithA(a);
  // NullPointerException, line 40, e.g. it wasn't OK to pass null for o you lunkhead
}

^ Возможно, экономит несколько циклов процессора за счет большого количества раздражающего кода. Однако во втором случае мы делаем меньше сравнений.

public void foo(Object a, Object b, Object c, Object d) {
  if (a == null) throw IllegalArgumentException("jackass");
  if (b == null) throw IllegalArgumentException("jackass");
  if (c == null) throw IllegalArgumentException("jackass");
  // But d is totally OK!
  // ...
  c.setSomeValueThatMayBeNull(d);
}

public void foo(Object a, Object b, Object c, Object d) {
  // ...
  c.setSomeValueThatMayBeNull(d);
  // Throws null pointer exception if c is null, but not if d is null. Which is basically the same as above
}

^ Контракт неявный из инструкции, а не случай исключения в начале метода. Не имеет другого недостатка.

public void foo(Object o) {
  if (o == null) {
    doTheBoogie();
  } else {
    doTheRobot();
  }
}

^ Плохо

public void foo(Object o, int b) {
  Bar value = o.findSomethingWhichMayExist(b);
  if (value == null)
    return;
  value.doSomething();
}

^ Используя значение null return, чтобы указать на отсутствие значения. OK.

Другая причина, по которой у людей возникают проблемы с NPE, заключается в том, что они не знают, как обрабатывать исключения. NPE никогда не должен быть showstopper. Соответствующее поведение заключается в том, чтобы уловить RuntimeException, предположительно, на гораздо более высоком (или ниже, в зависимости от того, как вы его видите) уровне в стеке вызовов, которое ловушки и сообщает об этом до "main". То есть, предполагая, что вы разрабатываете программу, которая должна быть более устойчивой и не может просто сбой при возникновении NPE.

Нижняя строка: никогда не ожидайте, что это будет действительная вещь для передачи в значениях null для параметров метода. И определенно не создавайте контракт для метода, который явно принимает значение null и рассматривает его как допустимое значение. Но, допустим, исключения из null-указателей произойдут, и пусть код завершится неудачно или не сработает, если это не имеет никакого значения, естественно.

Ответ 18

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

Вопрос задавался до 7 лет, но теперь у нас есть опция в java 8, и эта функция позволяет предотвратить NPE.

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

Ответ 19

Выбросить это исключение не является хорошей практикой в ​​некоторых случаях, и мне интересно, почему, когда вы уже поймали его с помощью оператора if?

если (ReturnValue == NULL)