IllegalArgumentException или NullPointerException для нулевого параметра? [закрыто]

У меня есть простой метод установки для свойства и nullне подходит для этого конкретного свойства. Я всегда разрывался в этой ситуации: я должен бросить IllegalArgumentException, или NullPointerException? От javadocs оба кажутся подходящими. Есть ли какой-то понятый стандарт? Или это всего лишь одна из тех вещей, которые вы должны делать, что хотите, и оба они действительно верны?

26 ОТВЕТОВ
РЕШЕНИЕ

Кажется, что IllegalArgumentExceptionвызывается для, если вы не хотите nullбыть допустимым значением, и NullPointerExceptionбудет выброшено, если вы пытаетесь использовать переменную, которая оказывается null.

298
14.05.2017 11:46:06
Следующие ответы на этот вопрос приводят убедительные аргументы в пользу того, что NullPointerException является правильным исключением: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; и stackoverflow.com/a/6358/372926 .
SamStephens 6.02.2014 23:09:17
IllegalArgumentExceptionнаходится в противоречии с Java Objects.requireNonNull (T) и Гуавой Preconditions.checkNotNull (T), которая выбрасывает NullPointerException. Тем не менее, правильный ответ определенно IllegalArgumentException описан в превосходном ответе Джейсона Коэна и в разделе комментариев .
matoni 22.07.2018 14:32:56

Если это setterметод и nullпередается ему, я думаю, что было бы больше смысла бросить IllegalArgumentException. NullPointerExceptionКажется, A имеет больше смысла в том случае, когда вы пытаетесь использовать null.

Таким образом, если вы используете его , и это null, NullPointer. Если он передается в и это null, IllegalArgument.

17
30.08.2016 10:11:03

Я склонен следить за дизайном библиотек JDK, особенно коллекций и параллелизма (Джошуа Блох, Даг Ли, эти ребята знают, как создавать надежные API). Во всяком случае, многие API в JDK активно выбрасывают NullPointerException.

Например, Javadoc для Map.containsKeyгосударств:

@throws NullPointerException, если ключ является нулевым, и эта карта не допускает нулевые ключи (необязательно).

Это совершенно справедливо, чтобы бросить свой собственный NPE. Соглашение состоит в том, чтобы включить имя параметра, который был нулевым, в сообщении об исключении.

Шаблон идет:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

Что бы вы ни делали, не допускайте установки плохого значения и генерируйте исключение позже, когда другой код пытается его использовать. Это делает отладку кошмаром. Вы всегда должны следовать принципу «быстро-неудачно».

70
3.11.2015 21:39:35
Пища для размышления: возможно, причина того, что NullPointerException не расширяет IllegalArgumentException, заключается в том, что первое может возникать в случаях, не связанных с аргументами метода.
Gili 29.12.2010 20:11:10
@Gili: возможно, эта проблема существует в первую очередь потому, что Java не поддерживает множественное наследование. Если Java поддерживает MI, вы сможете создать исключение, которое наследуется как от IllegalArgumentException, так и от NullPointerException.
Lie Ryan 1.03.2013 14:29:27
Сообщение не должно включать аргумент, так как оно всегда будет нулевым, давая: «null не должен быть нулевым», не очень полезно. :-) В противном случае, я согласен, вы можете сделать «богатый» NPE со значимым сообщением.
PhiLho 22.07.2013 15:21:03
Я должен согласиться - следуйте стандартным API, если сомневаетесь. Не все в API является оптимальным, но он поддерживается и повторяется сотнями разработчиков и используется миллионами программистов. Теперь в Java 7 у нас есть другой пример использования NPE таким образом; метод Objects.requireNonNull (T obj) - явно заданный для проверки того, что ссылки на объекты не равны NULL, четко указан для проверки параметров в методах / конструкторах и явно задан для выброса NPE, если объект имеет значение NULL. Конец
flamming_python 30.06.2014 17:48:28

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

-5
11.08.2008 13:20:39
Время выполнения не будет включать значимых сообщений.
mP. 31.03.2012 09:03:07
На самом деле этот комментарий может привести к другому мнению. Пусть ВМ говорит, NPEа программисты говорят IAEперед ВМ, если они хотят.
Jin Kwon 13.07.2012 02:22:10
Дорого? Я не думаю, что == null это так дорого ... Кроме того, нулевой аргумент может быть просто сохранен для последующего использования и будет генерировать исключение спустя долгое время после вызова метода, что усложнит отслеживание ошибки. Или вы можете создать дорогой объект перед использованием нулевого аргумента и так далее. Раннее обнаружение кажется хорошим вариантом.
PhiLho 22.07.2013 15:26:04
голосование против этого ответа - непонимание аппаратного обеспечения позади. Конечно, аппаратные проверки (которые выполняет CPU) дешевле, чем явные проверки. Разыменование нуля - это особый случай SegmentationFault (SegV) (доступ к странице, не принадлежащей процессу), который CPU / OS проверяет, а JRE обрабатывает как особый случай, вызывая исключение NullPointerException.
digital_infinity 11.08.2017 08:31:08

Общепринятая практика, если использовать IllegalArgumentException (String message), чтобы объявить параметр недействительным и дать как можно больше подробностей ... Так что сказать, что параметры были определены как нулевые, а исключение ненулевое, вы бы что-то сделали как это:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

У вас практически нет причин неявно использовать «NullPointerException». NullPointerException - это исключение, которое выдается виртуальной машиной Java при попытке выполнить код по нулевой ссылке (например, toString () ).

6
11.08.2008 19:43:49

Стандарт бросить NullPointerException. Обычно безошибочная «Эффективная Java» кратко обсуждает это в пункте 42 (первое издание), пункте 60 (второе издание) или пункте 72 (третье издание) «Пользу от использования стандартных исключений»:

«Возможно, все ошибочные вызовы методов сводятся к недопустимому аргументу или недопустимому состоянию, но другие исключения стандартно используются для определенных типов недопустимых аргументов и состояний. Если вызывающая сторона передает нуль в некотором параметре, для которого нулевые значения запрещены, соглашение предписывает, что Исключение NullPointerException, а не IllegalArgumentException. "

162
9.10.2018 09:48:06
Я категорически не согласен. Исключения NullPointerException должны создаваться только в том случае, если JVM случайно следует пустой ссылке. Именно эта разница помогает вам при вызове взглянуть на код в 3 часа утра.
Thorbjørn Ravn Andersen 29.05.2009 20:51:55
Я не обязательно согласен со стандартом (на самом деле я мог бы пойти по этому вопросу в любом случае), но это то, чем является стандартное использование во всем JDK, следовательно, эффективная Java обосновывает это. Я думаю, что это тот случай, когда вы выбираете, следует ли следовать стандарту или делать то, что вы считаете правильным. Если у вас нет очень веских причин (и это, безусловно, может подойти), лучше следовать стандартной практике.
GaryF 8.06.2009 10:28:24
Трассировка исключения показывает точку исключения, поэтому, если разница в типе исключения вызывает у вас ад или «разница, которая вам помогает», вы делаете что-то очень неправильно.
Jim Balter 31.01.2013 23:34:18
Фантазии и софистика. Чуть ниже MB пишет: «Обратите внимание, что аргументы о жесткой отладке являются фиктивными, потому что вы, конечно, можете предоставить сообщение NullPointerException, сообщающее, что было нулевым и почему оно не должно быть нулевым. Как и в случае IllegalArgumentException».
Jim Balter 7.07.2014 21:37:47
Как оригинальный ответчик здесь, позвольте мне сказать, что это не имеет большого значения. Это, конечно, не гарантирует 6 лет разговора. Выберите тот, который вам нравится, и будьте последовательны. Стандарт, как я указал, это NPE. Если вы предпочитаете IAE по тем или иным причинам, сделайте это. Просто будь последовательным.
GaryF 8.07.2014 08:38:05

Определения из ссылок на два вышеупомянутых исключения являются IllegalArgumentException: Брошенный, чтобы указать, что методу был передан недопустимый или неподходящий аргумент. NullPointerException: выдается, когда приложение пытается использовать значение NULL в случае, когда требуется объект.

Большая разница здесь заключается в том, что IllegalArgumentException предполагается использовать при проверке правильности аргумента метода. Предполагается, что NullPointerException будет использоваться всякий раз, когда объект «используется», когда он нулевой.

Я надеюсь, что это помогает поставить два в перспективе.

-1
16.08.2008 18:13:20
Важным моментом является то, что это приложение использует null, а не среду выполнения. Таким образом, между «когда методу был передан недопустимый или неподходящий аргумент» и «когда приложение использует нуль» довольно много совпадений. Теоретически, если приложение пропускает ноль для поля, которое требует ненулевое значение, оба критерия удовлетворяются.
Christopher Smith 9.12.2009 06:12:44

Не могу согласиться с тем, что говорится. Неудача рано, неудача быстро. Довольно хорошая Исключительная мантра.

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

Мои 2 цента

7
22.08.2008 11:11:35

Если это «сеттер» или где-то, что я получаю, чтобы член использовал позже, я склонен использовать IllegalArgumentException.

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

Если я переопределяю метод, я использую то, что использует переопределенный метод.

-1
28.08.2008 18:03:19

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

4
5.09.2008 10:34:05
JavaDoc в NPE придерживается другого мнения: «Приложения должны генерировать экземпляры этого класса, чтобы указать на другое незаконное использование нулевого объекта». Не будь таким категоричным
Donz 9.11.2010 08:56:45

Вы должны использовать IllegalArgumentException(IAE), а не NullPointerException(NPE) по следующим причинам:

Во-первых, NPD JavaDoc явно перечисляет случаи, когда NPE подходит. Обратите внимание, что все они выбрасываются средой выполнения, когда nullиспользуется не по назначению. Напротив, JavaDoc IAE не может быть более ясным: «Брошенный, чтобы указать, что метод был передан недопустимый или неподходящий аргумент». Да, это ты!

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

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

В-четвертых, все другие неверные данные параметров будут IAE, так почему бы не быть последовательными? Почему незаконность nullнастолько особенная, что она заслуживает отдельного исключения из всех других типов незаконных аргументов?

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

416
15.09.2016 08:11:13
Effective Java 2nd Edition, Item 60: «Возможно, все ошибочные вызовы методов сводятся к недопустимому аргументу или недопустимому состоянию, но другие исключения стандартно используются для определенных типов недопустимых аргументов и состояний. Если вызывающая сторона передает значение null в некотором параметре, для которого нулевые значения запрещены, соглашение предписывает, чтобы выбрасывалось исключение NullPointerException, а не IllegalArgumentException. Аналогичным образом, если вызывающая сторона передает значение вне диапазона в параметре, представляющем индекс, в последовательность, следует генерировать исключение IndexOutOfBoundsException, а не IllegalArgumentException. "
Gili 29.12.2010 20:15:30
JavaDoc для NPE также гласит следующее: «Приложения должны генерировать экземпляры этого класса, чтобы указать на другое незаконное использование нулевого объекта». Это может быть более ясно :(
R. Martinho Fernandes 25.01.2011 16:25:05
К сожалению, методы проверки Validate.notNull(commons lang) и Preconditions.checkNotNull(guava) оба бросают NPE :-(
Aaron Digulla 15.10.2012 15:43:36
Хотя в Guava также есть Preconditions.checkArgument ()
michaelok 17.12.2013 00:02:34
@AaronDigulla, из документа Guava: «Мы понимаем, что есть много веских аргументов в пользу использования IAE для нулевого аргумента. Фактически, если бы у нас была машина времени, чтобы вернуться назад> 15 лет, мы могли бы даже попытаться подтолкнуть вещи в в этом направлении. Однако мы решили придерживаться предпочтения JDK и Effective Java для NullPointerException. Если вы твердо уверены в том, что IAE правильно, у вас все еще есть checkArgument(arg != null), просто без удобства возврата arg, или вы можете создать локальная утилита для вашего проекта. " code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Arto Bendiken 28.10.2014 23:07:16

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

-1
9.09.2008 04:13:05
Извините, если программист оглядывается «случайным образом» при получении какого-либо исключения ... изменение имени исключения не сильно поможет.
Christopher Smith 9.12.2009 06:09:34

Это вопрос стиля "Священной войны". Другими словами, обе альтернативы хороши, но у людей будут свои предпочтения, которые они будут защищать до смерти.

20
17.10.2008 13:31:45
Нет, есть только один правильный ответ на этот вопрос, и это использование исключения throw IllegalArgument, когда входные данные в метод неверны. Кроме того, в среде разработчиков вы можете использовать утверждения для проверки правильности ввода и
Mr.Q 24.02.2019 12:20:04
@ Mr.Q И я думаю, что это NullPointerExceptionдолжно быть выброшено: это соглашение, которое использует JDK, и требует интерфейсов, оно более конкретное (как и IndexOutOfBoundsExceptionт. Д.) И т. Д.
Solomon Ucko 22.07.2019 20:28:16
kekekekkek ...: D
Yousha Aleayoub 25.11.2019 11:35:09

В этом случае IllegalArgumentException передает ясную информацию пользователю, используя ваш API, что «не должно быть нулевым». Как отмечали другие пользователи форума, вы можете использовать NPE, если хотите, если вы предоставляете нужную информацию пользователю, используя ваш API.

GaryF и tweakt удалили ссылки на «Эффективную Java» (которые, клянусь), которые рекомендуют использовать NPE. И, глядя на то, как создаются другие хорошие API, это лучший способ увидеть, как создать ваш API.

Еще один хороший пример - взглянуть на API Spring. Например, org.springframework.beans.BeanUtils.instantiateClass (конструктор ctor, Object [] args) имеет строку Assert.notNull (ctor, «Конструктор не должен быть нулевым»). Метод org.springframework.util.Assert.notNull (Object object, String message) проверяет, является ли переданный аргумент (объект) нулевым, и если это так, генерирует новое исключение IllegalArgumentException (message), которое затем перехватывается в орг. springframework.beans.BeanUtils.instantiateClass (...) метод.

-1
29.10.2008 16:20:26

Я хотел выделить аргументы Null из других недопустимых аргументов, поэтому я вывел исключение из IAE с именем NullArgumentException. Даже не имея необходимости читать сообщение об исключении, я знаю, что в метод был передан нулевой аргумент, и, прочитав сообщение, я выясняю, какой аргумент был нулевым. Я все еще ловлю исключение NullArgumentException с помощью обработчика IAE, но в моих журналах я могу быстро увидеть разницу.

4
17.01.2009 00:13:16
Я принял подход «бросить новый IllegalArgumentException (" foo == null ")". В любом случае вам нужно записать имя переменной (чтобы быть уверенным, что вы смотрите на правильное заявление и т. Д.)
Thorbjørn Ravn Andersen 29.05.2009 21:05:55

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

Хотя я чувствую, что создание чего-то вроде NullArgumentException или IllegalArgumentException более точно описывает исключительные обстоятельства, мои коллеги и я предпочли подчиниться совету Блоха по этому вопросу.

9
2.07.2009 04:47:14
Обратите внимание, что они удалили его из commons-lang3: apache-commons.680414.n4.nabble.com/…
artbristol 18.09.2013 10:47:26

Проголосовал за аргумент Джейсона Коэна, потому что он был хорошо представлен. Позвольте мне расчленить это шаг за шагом. ;-)

  • В JavaDoc NPE явно сказано: «другие незаконные использования нулевого объекта» . Если бы он был ограничен ситуациями, когда среда выполнения встречает ноль, а не должен, все такие случаи можно определить гораздо более кратко.

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

  • Я бы выбрал NPE над МИА по нескольким причинам

    • Более конкретно о характере незаконной операции
    • Логика, которая по ошибке допускает нулевые значения, имеет тенденцию сильно отличаться от логики, которая по ошибке допускает недопустимые значения. Например, если я проверяю данные, введенные пользователем, если получаю недопустимое значение, источником этой ошибки является конечный пользователь приложения. Если я получаю ноль, это ошибка программиста.
    • Неверные значения могут вызывать такие вещи, как переполнение стека, ошибки нехватки памяти, синтаксический анализ исключений и т. Д. Действительно, большинство ошибок в какой-то момент обычно представляют собой недопустимое значение при вызове некоторых методов. По этой причине я вижу IAE как НАИБОЛЕЕ ОБЩЕЕ из всех исключений в RuntimeException.
  • На самом деле, другие недопустимые аргументы могут привести к разным исключениям. UnknownHostException , FileNotFoundException , различные исключения синтаксических ошибок, IndexOutOfBoundsException , ошибки аутентификации и т. Д., И т. Д.

В целом, я чувствую, что NPE сильно порочен, потому что традиционно ассоциируется с кодом, который не соответствует принципу fast fast . Это, плюс неспособность JDK заполнить NPE строкой сообщения, действительно породила сильное негативное мнение, которое не вполне обосновано. На самом деле, разница между NPE и IAE с точки зрения времени выполнения - это просто название. С этой точки зрения, чем точнее вы указали имя, тем больше ясности вы дадите звонящему.

44
11.07.2012 13:53:22
Разница между большинством непроверенных исключений заключается только в названии.
Thorbjørn Ravn Andersen 7.07.2014 02:33:24

Я был за то, чтобы выбрасывать IllegalArgumentExceptionнулевые параметры до сегодняшнего дня, пока я не заметил java.util.Objects.requireNonNullметод в Java 7. С этим методом вместо выполнения:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

ты можешь сделать:

Objects.requireNonNull(param);

и он выдаст, NullPointerExceptionесли параметр, который вы передаете это null.

Учитывая, что этот метод находится в центре внимания, java.utilя считаю его существование довольно убедительным признаком того, что бросание NullPointerException- это «способ ведения дел на Java».

Я думаю, что я во всяком случае решил.

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

Еще одним преимуществом NullPointerExceptionявляется то, что в коде с высокой производительностью вы можете обойтись без явной проверки нуля (и NullPointerExceptionс дружественным сообщением об ошибке), и просто полагаться на то, что NullPointerExceptionвы получите автоматически при вызове метода для нуля параметр. При условии, что вы вызываете метод быстро (т. Е. Быстро терпите неудачу), вы получаете тот же эффект, но не совсем удобный для разработчика. В большинстве случаев, вероятно, лучше явно проверить и выдать полезное сообщение, чтобы указать, какой параметр был нулевым, но хорошо иметь возможность изменить это, если производительность диктует, не нарушая опубликованный контракт метода / конструктора.

137
10.11.2012 12:57:14
Гуава Preconditions.checkNotNull(arg)также бросает NPE.
assylias 14.10.2012 16:55:58
Это на самом деле не добавляет веса к NullPointerException для недопустимых нулевых аргументов. Как JDK requireNonNull (), так и Guava checkNotNull () могут быть вызваны в любом месте кода с любым объектом. Вы можете вызвать их внутри цикла, например. requireNotNull () и checkNotNull () не могли предположить, что они вызываются с некоторыми аргументами метода и генерируют исключение IllegalArgumentException. Обратите внимание, что Guava также имеет Preconditions.checkArgument (), который генерирует исключение IllegalArgumentException.
Bogdan Calmac 8.03.2013 18:37:59
Справедливо замечание Богдана, хотя я подозреваю, что типичное (и обычно предполагаемое) использование requireNonNull предназначено для проверки аргументов. Если бы вам нужно было проверить, что что-то не является нулевым в цикле, я бы подумал, что утверждение будет типичным способом.
MB. 8.08.2013 14:41:07
Я думаю, что JavaDoc Object.requireNonNull () добавляет вес к аргументу: «Этот метод предназначен в первую очередь для проверки параметров в методах и конструкторах»
Richard Zschech 2.02.2015 14:42:41
Имейте в виду, что аргумент производительности в пользу неявных нулевых проверок часто недопустим. JIT может распознавать пользовательские проверки на ноль и исключать следующую подразумеваемую проверку на ноль и / или использовать один и тот же набор оптимизаций для любого типа проверки на ноль. Посмотрите эту вики для получения дополнительной информации, в частности: Пользовательские проверки на ноль в большинстве случаев функционально идентичны проверкам, вставленным JVM. Конечно, если вы делаете что-то более необычное в своем нуле, например, в пользовательских сообщениях, эта оптимизация может не применяться.
BeeOnRope 2.11.2016 23:17:05

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

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
4
13.05.2012 00:14:56
Это удвоит накладные расходы на создание исключений и не очень поможет, так как перехват NullPointerExceptionничего не даст. Единственное, что может помочь IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, но у нас нет множественного наследования.
maaartinus 30.01.2014 11:31:59
Я считаю, что более конкретные исключения должны быть заключены в более общие исключения. NPE для выражения, а IAE для метода. Поскольку методы содержат операторы, содержащие выражения, IAE является более общим.
Sgene9 26.01.2018 16:46:45
Что касается накладных расходов, я понятия не имею. Но так как трассировки стека в основном были бы идентичны, за исключением того, что имя исключения изменилось в середине, я думаю, что для двойных исключений не должно быть слишком много служебной информации. Если кто-то беспокоится о накладных расходах, он может использовать операторы if, чтобы вернуть ноль или -1, вместо того, чтобы выдавать исключение.
Sgene9 26.01.2018 16:53:28

Некоторые коллекции предполагают, что nullотклонено использование NullPointerExceptionвместо IllegalArgumentException. Например, если вы сравните набор, содержащий nullнабор, который отклоняет null, первый набор вызовет containsAllдругой и поймает его NullPointerException- но не IllegalArgumentException. (Я смотрю на реализацию AbstractSet.equals.)

Вы могли бы обоснованно утверждать, что использование непроверенных исключений таким способом является антипаттерном, что сравнение коллекций, которые содержат, nullс коллекциями, которые не могут содержать, nullявляется вероятной ошибкой, которая действительно должна вызвать исключение, или что nullдобавление коллекции вообще является плохой идеей. , Тем не менее, если вы не готовы сказать, что это equalsдолжно вызвать исключение в таком случае, вы застряли, вспомнив, что NullPointerExceptionтребуется в определенных обстоятельствах, но не в других. («IAE до NPE, кроме как после« c »...»)

5
9.11.2012 16:30:23
Я не вижу, как в контейнере выбрасывается NPE в зависимости от элемента внутри коллекции. Единственная причина, по которой NPE выбрасывается (afaict), заключается в том, что сама коллекция является нулевой (в этом случае NPE выбрасывается, потому что она пытается получить доступ к своему итератору). Это, однако, поднимает вопрос о том, нужно ли проверять нулевой ввод или же он должен распространяться до тех пор, пока он не попытается получить доступ.
Alowaniak 8.07.2016 12:27:34
new TreeSet<>().containsAll(Arrays.asList((Object) null));бросает, NPEпотому что Listсодержит null.
Chris Povirk 8.07.2016 14:13:55
И действительно, TreeSet # содержит броски NPE «если указанный элемент имеет значение null и этот набор использует естественное упорядочение или его компаратор не допускает нулевые элементы». Только посмотрел на AbstractSet, который допускает ноль, мой плохой. Лично я нахожу это странным, но он не просто возвращает false, поскольку в этом случае невозможно добавить ноль.
Alowaniak 12.07.2016 15:16:22

Создание исключения, исключающего nullаргументы ( NullPointerExceptionили пользовательского типа), делает автоматизированное nullтестирование более надежным. Это автоматизированное тестирование может быть сделано с отражением и набором значений по умолчанию, как в гуавы «с NullPointerTester. Например, NullPointerTesterпопытался бы вызвать следующий метод ...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

... с двумя списками аргументов: "", nullи null, ImmutableList.of(). Было бы проверить, что каждый из этих вызовов бросает ожидаемый NullPointerException. Для этой реализации передача nullсписка не производит NullPointerException. Это, однако, случается, IllegalArgumentExceptionпотому NullPointerTesterчто использует строку по умолчанию "". Если NullPointerTesterожидает только NullPointerExceptionдля nullзначений, он ловит ошибку. Если он ожидает IllegalArgumentException, он пропускает это.

6
9.11.2012 16:30:07

На самом деле, вопрос о создании IllegalArgumentException или NullPointerException, на мой взгляд, является лишь «священной войной» для меньшинства с неполным пониманием обработки исключений в Java. В общем, правила просты и таковы:

  • Нарушения ограничения аргумента должны указываться как можно быстрее (-> fast fail), чтобы избежать недопустимых состояний, которые намного сложнее отлаживать
  • в случае недействительного нулевого указателя по какой-либо причине, сгенерируйте исключение NullPointerException
  • в случае недопустимого индекса массива / коллекции, бросить ArrayIndexOutOfBounds
  • в случае отрицательного размера массива / коллекции, сгенерируйте исключение NegativeArraySizeException
  • в случае недопустимого аргумента, который не описан выше, и для которого у вас нет другого более конкретного типа исключения, выведите IllegalArgumentException в качестве корзины для мусора
  • с другой стороны, в случае нарушения ограничения WITHIN A FIELD, которого нельзя было избежать быстрым отказом по какой-либо уважительной причине, перехватите и перебросьте как IllegalStateException или более конкретное проверенное исключение. Никогда не пропускайте исходное исключение NullPointerException, ArrayIndexOutOfBounds и т. Д. В этом случае!

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

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

(2) Отображение исключений фактически приводит к другому типу аномалии, вызванной одиночным наследованием: все исключения Java являются классами и поэтому поддерживают только одиночное наследование. Следовательно, нет никакого способа создать исключение, которое действительно скажет и NullPointerException, и IllegalArgumentException, поскольку подклассы могут наследоваться только от одного или другого. Поэтому создание исключения IllegalArgumentException в случае нулевого аргумента усложняет пользователям API различие между проблемами, когда программа пытается программно исправить проблему, например, путем ввода значений по умолчанию в повтор вызова!

(3) Отображение фактически создает опасность маскирования ошибок: для того, чтобы отобразить нарушения ограничения аргументов в IllegalArgumentException, вам необходимо кодировать внешний try-catch внутри каждого метода, который имеет какие-либо ограниченные аргументы. Однако просто перехватить исключение RuntimeException в этом блоке перехвата не может быть и речи, потому что это рискует отобразить документированные исключения RuntimeException, созданные вашими свободными методами, в IllegalArgumentException, даже если они не вызваны нарушениями ограничения аргумента. Поэтому вам нужно быть очень конкретным, но даже эти усилия не защитят вас от случая, когда вы случайно отобразите недокументированное исключение времени выполнения другого API (например, ошибку) в IllegalArgumentException вашего API.

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

7
31.12.2012 17:44:57

В соответствии с вашим сценарием, IllegalArgumentExceptionэто лучший выбор, потому что nullне является действительным значением для вашей собственности.

3
5.06.2015 12:46:20

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

IllegalArgumentException бросается, когда метод получает аргумент, отформатированный не так, как ожидает метод.

4
25.11.2019 11:38:29

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

0
18.08.2016 08:40:06

В качестве субъективного вопроса это должно быть закрыто, но так как оно все еще открыто:

Это часть внутренней политики, используемой на моем предыдущем месте работы, и она работала очень хорошо. Это все из памяти, поэтому я не могу вспомнить точную формулировку. Стоит отметить, что они не использовали проверенные исключения, но это выходит за рамки вопроса. Непроверенные исключения, которые они использовали, попали в 3 основные категории.

NullPointerException: не бросать намеренно. NPE должны создаваться только виртуальной машиной при разыменовании нулевой ссылки. Все возможные усилия должны быть предприняты, чтобы гарантировать, что они никогда не будут брошены. @Nullable и @NotNull должны использоваться в сочетании с инструментами анализа кода, чтобы найти эти ошибки.

IllegalArgumentException: генерируется, когда аргумент функции не соответствует общедоступной документации, так что ошибка может быть идентифицирована и описана в терминах переданных аргументов. Ситуация OP попадает в эту категорию.

IllegalStateException: генерируется, когда вызывается функция и ее аргументы либо неожиданны в момент их передачи, либо несовместимы с состоянием объекта, членом которого является метод.

Например, были две внутренние версии IndexOutOfBoundsException, используемые в вещах, которые имели длину. Один подкласс IllegalStateException, используемый, если индекс был больше, чем длина. Другой подкласс IllegalArgumentException, используемый, если индекс был отрицательным. Это потому, что вы можете добавить больше объектов к объекту, и аргумент будет действительным, а отрицательное число никогда не будет действительным.

Как я уже сказал, эта система работает очень хорошо, и потребовался кто-то, чтобы объяснить, почему существует различие: «В зависимости от типа ошибки вам довольно просто понять, что делать. Даже если вы не можете понять, на самом деле из того, что пошло не так, вы можете выяснить, где отловить эту ошибку и создать дополнительную информацию для отладки.

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

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

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

В любом случае, он хотел, чтобы вы могли копировать только IllegalArgumentAssertions в стек. Вы не можете распространять IllegalStateExceptions или NullPointerExceptions вверх по стеку, поскольку они имеют какое-то отношение к вашей функции.

5
25.07.2018 15:06:45