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

547

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

Майк Стоун
источник

Ответы:

299

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

Грег Хурлман
источник
33
Следующие ответы на этот вопрос приводят убедительные аргументы в пользу того, что NullPointerException является правильным исключением: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; и stackoverflow.com/a/6358/372926 .
SamStephens
2
IllegalArgumentExceptionнаходится в противоречии с Java Objects.requireNonNull (T) и Guava Preconditions.checkNotNull (T), который выдает NullPointerException. Тем не менее, правильный ответ определенно IllegalArgumentException описан в превосходном ответе Джейсона Коэна и в разделе комментариев .
Матони
417

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

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

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

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

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

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

Джейсон Коэн
источник
120
Effective Java 2nd Edition, Item 60: «Возможно, все ошибочные вызовы методов сводятся к недопустимому аргументу или недопустимому состоянию, но другие исключения стандартно используются для определенных типов недопустимых аргументов и состояний. нулевые значения запрещены, соглашение предписывает, чтобы выбрасывалось исключение NullPointerException, а не IllegalArgumentException. Аналогичным образом, если вызывающая сторона передает значение вне диапазона в параметре, представляющем индекс, в последовательность, должно генерироваться исключение IndexOutOfBoundsException, а не IllegalArgumentException. "
Гили
33
JavaDoc для NPE также гласит следующее: «Приложения должны генерировать экземпляры этого класса, чтобы указать на другое незаконное использование нулевого объекта». Это может быть более ясно :(
Р. Мартиньо Фернандес
12
К сожалению, методы проверки Validate.notNull(commons lang) и Preconditions.checkNotNull(guava) оба бросают NPE :-(
Аарон Дигулла
2
Хотя Guava также имеет Preconditions.checkArgument ()
создает исключение
16
@AaronDigulla, из документации по Guava: «Мы понимаем, что есть много веских аргументов в пользу использования IAE для нулевого аргумента. На самом деле, если бы у нас была машина времени, чтобы вернуться назад> 15 лет, мы могли бы даже попытаться подтолкнуть вещи в это направление. Однако мы решили придерживаться предпочтения JDK и Effective Java для NullPointerException. Если вы твердо уверены в том, что IAE правильно, у вас все еще есть checkArgument(arg != null), просто без удобства возврата arg, или вы можете создать локальная утилита для вашего проекта. " code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Арто Бендикен,
162

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

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

GaryF
источник
95
Я категорически не согласен. Исключения NullPointerException должны создаваться только в том случае, если JVM случайно следует пустой ссылке. Именно эта разница помогает вам при вызове взглянуть на код в 3 часа утра.
Торбьерн Равн Андерсен
26
Я не обязательно согласен со стандартом (на самом деле я мог бы пойти по этому вопросу в любом случае), но это то, чем является стандартное использование во всем JDK, следовательно, эффективная Java обосновывает это. Я думаю, что это случай выбора, следовать ли стандарту или делать то, что, по вашему мнению, правильно. Если у вас нет очень веских причин (и это, безусловно, может соответствовать требованиям), лучше следовать стандартной практике.
GaryF
21
Трассировка исключения показывает точку исключения, поэтому, если разница в типе исключения вызывает у вас ад или «разница, которая вам помогает», вы делаете что-то очень неправильно.
Джим Балтер
8
Фантазии и софистика. Чуть ниже MB пишет: «Обратите внимание, что аргументы о жесткой отладке являются фиктивными, потому что вы, конечно, можете предоставить сообщение NullPointerException, сообщающее, что было нулевым и почему оно не должно быть нулевым. Как и в случае IllegalArgumentException».
Джим Балтер
10
Как оригинальный ответчик здесь, позвольте мне сказать, что это не имеет большого значения. Это, конечно, не гарантирует 6 лет разговора. Выберите тот, который вам нравится, и будьте последовательны. Стандарт, как я указал, это NPE. Если вы предпочитаете IAE по тем или иным причинам, сделайте это. Просто будьте последовательны.
GaryF
138

Я был за то, чтобы выбрасывать 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вы получите автоматически при вызове метода с нулевым значением параметр. При условии, что вы вызываете метод быстро (т. Е. Быстро терпите неудачу), вы получаете тот же эффект, но не совсем удобный для разработчика. В большинстве случаев, вероятно, лучше явно проверить и выдать полезное сообщение, чтобы указать, какой параметр был пустым, но хорошо иметь возможность изменить это, если производительность диктует, не нарушая опубликованный контракт метода / конструктора.

MB.
источник
14
Гуава Preconditions.checkNotNull(arg)также бросает NPE.
assylias
14
Это на самом деле не добавляет веса к NullPointerException для недопустимых нулевых аргументов. И JDK requireNonNull (), и Guava checkNotNull () могут вызываться в любом месте кода с любым объектом. Вы можете вызвать их внутри цикла, например. requireNotNull () и checkNotNull () не могли предположить, что они вызываются с некоторыми аргументами метода и генерируют исключение IllegalArgumentException. Обратите внимание, что Guava также имеет Preconditions.checkArgument (), который генерирует исключение IllegalArgumentException.
Богдан Калмак
2
Справедливо по словам Богдана, хотя я подозреваю, что типичное (и обычно предполагаемое) использование requireNonNull предназначено для проверки аргументов. Если бы вам нужно было проверить, что что-то не является нулевым в цикле, я бы подумал, что утверждение будет типичным способом.
МБ.
15
Я думаю, что JavaDoc Object.requireNonNull () добавляет вес к аргументу: «Этот метод предназначен в первую очередь для проверки параметров в методах и конструкторах»
Ричард Зсеч
Имейте в виду, что аргумент производительности в пользу неявных нулевых проверок часто недопустим. JIT может распознавать пользовательские проверки на нуль и исключать следующую подразумеваемую проверку на ноль и / или использовать один и тот же набор оптимизаций для любого типа проверки на ноль. Посмотрите эту вики для получения дополнительной информации, в частности: Пользовательские проверки на ноль в большинстве случаев функционально идентичны проверкам, вставленным JVM. Конечно, если вы делаете что-то более изворотливое в своем нуле, например, в пользовательских сообщениях, эта оптимизация может не применяться.
BeeOnRope
70

Я склонен следить за дизайном библиотек 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");  
    }  
}

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

Марк Ренуф
источник
3
Пища для размышления: возможно, причина того, что NullPointerException не расширяет IllegalArgumentException, заключается в том, что первое может возникать в случаях, не связанных с аргументами метода.
Гили
2
@Gili: возможно, эта проблема существует в первую очередь потому, что Java не поддерживает множественное наследование. Если Java поддерживает MI, вы сможете создать исключение, которое наследуется как от IllegalArgumentException, так и от NullPointerException.
Ли Райан
7
Сообщение не должно включать аргумент, так как оно всегда будет нулевым, давая: «null не должен быть нулевым», не очень полезно. :-) В противном случае, я согласен, вы можете сделать «богатый» NPE со значимым сообщением.
PhiLho
5
Я должен согласиться - следуйте стандартным API, если сомневаетесь. Не все в API является оптимальным, но он поддерживается и повторяется сотнями разработчиков и используется миллионами программистов. Теперь в Java 7 у нас есть другой пример использования NPE таким образом; метод Objects.requireNonNull (T obj) - явно заданный для проверки того, что ссылки на объекты не равны NULL, четко указан для проверки параметров в методах / конструкторах и явно задан для выброса NPE, если объект имеет значение NULL. Конец
flamming_python
44

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

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

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

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

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

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

Кристофер Смит
источник
Разница между большинством непроверенных исключений заключается только в названии.
Турбьёрн Равн Андерсен
20

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

Стив Маклеод
источник
Нет, есть только один правильный ответ на этот вопрос, и это использование исключения throw IllegalArgument, когда входные данные в метод неверны. Кроме того, в среде разработчиков вы можете использовать утверждения для проверки правильности ввода и
выдачи
@ Mr.Q И я думаю, что это NullPointerExceptionдолжно быть выброшено: это соглашение, которое использует JDK, и требует интерфейсов, оно более конкретное (как и IndexOutOfBoundsExceptionт. Д.) И т. Д.
Solomon Ucko
kekekekkek ...: D
Юша Алеауб
17

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

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

Джереми Приветт
источник
9

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

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

Брайан Т. Грант
источник
7
Обратите внимание, что они удалили его из commons-lang3: apache-commons.680414.n4.nabble.com/…
artbristol
7

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

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

Мои 2 цента

Аллен Лалонд
источник
7

На самом деле, вопрос о создании 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, вам необходимо кодировать внешнюю попытку в каждом методе, который имеет какие-либо ограниченные аргументы. Однако просто перехватить RuntimeException в этом блоке перехвата не может быть и речи, потому что это рискует отобразить документированные RuntimeException, выброшенные вашими методами libery, в IllegalArgumentException, даже если они не вызваны нарушениями ограничения аргумента. Таким образом, вы должны быть очень конкретны, но даже это усилие не защитит вас от случая, когда вы случайно отобразите недокументированное исключение времени выполнения другого API (т.е. ошибку) в IllegalArgumentException вашего API.

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

Саша Баумейстер
источник
6

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

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

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

Клод Хоул
источник
6

Создание исключения, исключающего 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, он пропускает это.

Крис Повирк
источник
5

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

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

Крис Повирк
источник
Я не вижу, как в контейнере выбрасывает NPE в зависимости от элемента внутри коллекции. Единственная причина, по которой NPE выбрасывается (afaict), заключается в том, что сама коллекция пуста (в этом случае NPE выбрасывается, потому что пытается получить доступ к своему итератору). Это, однако, поднимает вопрос о том, следует ли проверять нулевой ввод или же он должен распространяться до тех пор, пока он не попытается получить доступ.
Alowaniak
2
new TreeSet<>().containsAll(Arrays.asList((Object) null));бросает NPEпотому что Listсодержит null.
Крис Повирк
1
И действительно, TreeSet # содержит броски NPE «если указанный элемент имеет значение null и этот набор использует естественное упорядочение или его компаратор не допускает нулевые элементы». Только посмотрел на AbstractSet, который допускает ноль, мой плохой. Лично я нахожу это странным, он не просто возвращает false, хотя в этом случае невозможно добавить ноль.
Alowaniak
5

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

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

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

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

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

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

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

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

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

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

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

Бен Зайдель
источник
4

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


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

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

Джейсон Фричер
источник
Я применил подход «throw new IllegalArgumentException (" foo == null ")". В любом случае вам нужно записать имя переменной (чтобы быть уверенным, что вы смотрите на правильное заявление и т. Д.)
Thorbjørn Ravn Andersen
4

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

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
Луис Даниэль Меса Веласкес
источник
1
Это удвоит накладные расходы на создание исключений и не очень поможет, так как перехват NullPointerExceptionничего не даст. Единственное, что может помочь IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, но у нас нет множественного наследования.
Maaartinus
Я считаю, что более конкретные исключения должны быть заключены в более общие исключения. NPE для выражения, а IAE для метода. Поскольку методы содержат операторы, содержащие выражения, IAE является более общим.
Sgene9
Что касается накладных расходов, я понятия не имею. Но так как трассировки стека в основном были бы идентичны, за исключением того, что имя исключения изменилось в середине, я думаю, что для двойных исключений не должно быть слишком много служебной информации. Если кто-то беспокоится о накладных расходах, он может использовать операторы if, чтобы вернуть ноль или -1, вместо того, чтобы выдавать исключение.
Sgene9
4

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

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

Нитеш Соомани
источник
3

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

Лео
источник
0

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

Виджей
источник
-1

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

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

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

martinatime
источник
1
Важным моментом является то, что это приложение использует null, а не среду выполнения. Таким образом, между «когда метод был передан недопустимый или неподходящий аргумент» и «когда приложение использует ноль», существует довольно большое совпадение. Теоретически, если приложение передает значение NULL для поля, которое требует ненулевое значение, оба критерия выполняются.
Кристофер Смит
-1

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

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

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

Эриксон
источник
-1

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

Уилл Сарджент
источник
4
Извините, если программист оглядывается «случайным образом» при получении какого-либо исключения ... изменение имени исключения не сильно поможет.
Кристофер Смит
-1

В этом случае 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 (...) метод.


источник
-5

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

jassuncao
источник
Время выполнения не будет включать значимых сообщений.
мП
На самом деле этот комментарий может привести к другому мнению. Пусть ВМ говорит, NPEно программисты говорят IAEперед ВМ, если они хотят.
Джин Квон
1
Дорогой? Я не думаю, что == null это так дорого ... Кроме того, нулевой аргумент может быть просто сохранен для последующего использования и будет генерировать исключение спустя долгое время после вызова метода, что усложнит отслеживание ошибки. Или вы можете создать дорогой объект перед использованием нулевого аргумента и так далее. Раннее обнаружение кажется хорошим вариантом.
Фил Фил
голосование против этого ответа - непонимание аппаратного обеспечения. Конечно, аппаратные проверки (которые выполняет процессор) дешевле, чем явные проверки. Разыменование нуля - это особый случай SegmentationFault (SegV) (доступ к странице, не принадлежащей процессу), который CPU / OS проверяет, а JRE обрабатывает как особый случай, вызывая исключение NullPointerException.
digital_infinity