Это нормально, чтобы бросить NullPointerException программно?

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

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

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

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

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

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

?

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

19 ответов


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

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

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


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

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

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

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

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

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

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


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

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


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

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

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

С другой стороны, javadoc говорит:

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

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


конечно, нет универсального закона против бросания 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 является индикатором некоторого состояния системы, которое вы действительно можете связь, используйте исключение, которое передает это состояние. Есть не так много случаев, о которых я могу думать, где имеет смысл проверять null ссылку только на chuck nullpointer. Обычно очень следующей строке кода бы бросил в любом случае, появляется сообщение об (или что-то более информативное)!


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

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


на 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. 

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

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

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


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


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


книга, которую я назвал Java О'Рейли в двух словах который написан экспертом, перечисляет это определение для NullPointerException:

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

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


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

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


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


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


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


Абсолютно да.

даже 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;
}

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

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

это нормально, чтобы бросить Исключение NullPointerException программно?

Java API doc для 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.) И есть много классов, которые используют NPEs таким образом, по существу, как частный случай IllegalArgumentException.

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

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


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

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

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

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

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

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

люди берут проблему с 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's 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's 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();
  }
}

^ Плохо!--8-->

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

^ использование возвращаемого значения null для указания отсутствия значения. ЛАДНО.

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

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


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

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

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


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

if (returnValue==null)