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

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

26 ответов


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


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

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

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

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

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

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


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

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


Я был за то, чтобы бросать 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 говоря, что было null и почему это не должно быть null. Так же, как с IllegalArgumentException.

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


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

например, Javadoc для Map.containsKey гласит:

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

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

шаблон идет:

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

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


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

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

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

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

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

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


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


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

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


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

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


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

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

Мои 2 Цента


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

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

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


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

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

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

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

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

(3) отображение фактически создает опасность маскировки ошибок: для отображения нарушений ограничений аргументов в IllegalArgumentException вам нужно будет закодировать внешний try-catch в каждом методе, который имеет любые ограниченные аргументы. Однако просто поймать RuntimeException в этом блоке catch не может быть и речи, потому что это рискует сопоставление документированных RuntimeExceptions, брошенных методами libery, используемыми в вашем, В IllegalArgumentException, даже если они не вызваны нарушениями ограничений аргументов. Поэтому вам нужно быть очень конкретным, но даже это усилие не защищает вас от случая, когда вы случайно сопоставляете недокументированное исключение времени выполнения другого API (т. е. ошибку) в IllegalArgumentException вашего ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС. Поэтому даже самое тщательное сопоставление рискует замаскировать ошибки программирования других создателей библиотек как нарушения ограничений аргументов пользователей вашего метода,что является просто Хиллари!

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


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


бросать исключение для null аргументов (будь то NullPointerException или пользовательский тип) делает automated null тестирование более надежным. Это автоматическое тестирование может быть выполнено с отражением и набором значений по умолчанию, как в гуавы ' s 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, он скучает по нему.


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

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

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

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

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

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

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

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

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

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

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


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


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

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

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

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


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

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


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


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


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

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

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


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

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

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


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


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

GaryF и tweakt отбросили" эффективные Java " (которые я клянусь) ссылки, которые рекомендуют использовать NPE. И глядя на то, как строятся другие хорошие API, лучший способ увидеть, как построить свой ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС.

еще один хороший пример-посмотреть на Spring APIs. Например, орг.springframework.зернышки.BeanUtils.instantiateClass (конструктор ctor, Object[] args) имеет Assert.notNull (ctor, "конструктор не должен быть null") строка. орг.springframework.утиль.Утверждать.метод notNull (Object object, String message) проверяет, является ли переданный аргумент (object) нулевым, и если это так, он создает новое исключение IllegalArgumentException (message), которое затем поймано в орг.springframework.зернышки.BeanUtils.instantiateClass(...) метод.


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