У меня есть простой метод установки для свойства и null
не подходит для этого конкретного свойства. Я всегда разрывался в этой ситуации: я должен бросить IllegalArgumentException
, или NullPointerException
? От javadocs оба кажутся подходящими. Есть ли какой-то понятый стандарт? Или это всего лишь одна из тех вещей, которые вы должны делать, что хотите, и оба они действительно верны?
547
IllegalArgumentException
находится в противоречии с Java Objects.requireNonNull (T) и Guava Preconditions.checkNotNull (T), который выдаетNullPointerException
. Тем не менее, правильный ответ определенноIllegalArgumentException
описан в превосходном ответе Джейсона Коэна и в разделе комментариев .Вы должны использовать
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 не является достаточным аргументом, чтобы превзойти эти другие соображения.
источник
Validate.notNull
(commons lang) иPreconditions.checkNotNull
(guava) оба бросают NPE :-(checkArgument(arg != null)
, просто без удобства возврата arg, или вы можете создать локальная утилита для вашего проекта. " code.google.com/p/guava-libraries/wiki/IdeaGraveyardСтандарт бросить
NullPointerException
. Обычно безошибочная «Эффективная Java» кратко обсуждает это в пункте 42 (первое издание), пункте 60 (второе издание) или пункте 72 (третье издание) «Пользу от использования стандартных исключений»:источник
Я был за то, чтобы выбрасывать
IllegalArgumentException
нулевые параметры до сегодняшнего дня, пока я не заметилjava.util.Objects.requireNonNull
метод в Java 7. С этим методом вместо выполнения:ты можешь сделать:
и он выдаст,
NullPointerException
если параметр, который вы передаете этоnull
.Учитывая, что этот метод находится в центре внимания,
java.util
я считаю его существование довольно убедительным признаком того, что бросаниеNullPointerException
- это «способ ведения дел на Java».Я думаю, что я во всяком случае решил.
Обратите внимание, что аргументы о жесткой отладке являются поддельными, потому что вы, конечно, можете предоставить сообщение о
NullPointerException
том, что является нулевым и почему оно не должно быть нулевым. Прямо как сIllegalArgumentException
.Еще одним преимуществом
NullPointerException
является то, что в коде с высокой производительностью, критическим для производительности, можно обойтись без явной проверки на нулевое значение (иNullPointerException
дружественным сообщением об ошибке) и просто полагаться на то, чтоNullPointerException
вы получите автоматически при вызове метода с нулевым значением параметр. При условии, что вы вызываете метод быстро (т. Е. Быстро терпите неудачу), вы получаете тот же эффект, но не совсем удобный для разработчика. В большинстве случаев, вероятно, лучше явно проверить и выдать полезное сообщение, чтобы указать, какой параметр был пустым, но хорошо иметь возможность изменить это, если производительность диктует, не нарушая опубликованный контракт метода / конструктора.источник
Preconditions.checkNotNull(arg)
также бросает NPE.Я склонен следить за дизайном библиотек JDK, особенно коллекций и параллелизма (Джошуа Блох, Даг Ли, эти ребята знают, как создавать надежные API). Во всяком случае, многие API в JDK активно выбрасывают
NullPointerException
.Например, Javadoc для
Map.containsKey
государств:Это совершенно справедливо, чтобы бросить свой собственный NPE. Соглашение состоит в том, чтобы включить имя параметра, который был нулевым, в сообщении об исключении.
Шаблон идет:
Что бы вы ни делали, не допускайте установки плохого значения и генерируйте исключение позже, когда другой код пытается его использовать. Это делает отладку кошмаром. Вы всегда должны следовать принципу «быстро-неудачно».
источник
Проголосовал за аргумент Джейсона Коэна, потому что он был хорошо представлен. Позвольте мне расчленить это шаг за шагом. ;-)
В JavaDoc NPE явно сказано: «другие виды незаконного использования нулевого объекта» . Если бы он был ограничен ситуациями, когда среда выполнения встречает ноль, а не должен, все такие случаи можно определить гораздо более кратко.
Ничего не поделаешь, если вы предполагаете, что что-то не так, но при условии, что инкапсуляция применяется правильно, вам действительно не нужно заботиться или не обращать внимания на то, неправильно ли была разыменована ссылка на нуль, по сравнению с тем, обнаружил ли метод неподходящий нуль и вызвал исключение.
Я бы выбрал NPE над МИА по нескольким причинам
На самом деле, другие недопустимые аргументы могут привести к разным исключениям. UnknownHostException , FileNotFoundException , различные исключения синтаксических ошибок, IndexOutOfBoundsException , ошибки аутентификации и т. Д. И т. Д. И т. Д.
В целом, я чувствую, что NPE сильно порочен, потому что традиционно ассоциируется с кодом, который не соответствует принципу fast fast . Это, плюс неспособность JDK заполнить NPE строкой сообщения, действительно породила сильное негативное мнение, которое не вполне обосновано. На самом деле, разница между NPE и IAE с точки зрения времени выполнения - это просто название. С этой точки зрения, чем точнее вы указали имя, тем больше ясности вы дадите звонящему.
источник
Это вопрос стиля «Священная война». Другими словами, обе альтернативы хороши, но у людей будут свои предпочтения, которые они будут защищать до смерти.
источник
NullPointerException
должно быть выброшено: это соглашение, которое использует JDK, и требует интерфейсов, оно более конкретное (как иIndexOutOfBoundsException
т. Д.) И т. Д.Если это
setter
метод иnull
передается ему, я думаю, что было бы более разумно броситьIllegalArgumentException
.NullPointerException
Кажется, A имеет больше смысла в том случае, когда вы пытаетесь использоватьnull
.Таким образом, если вы используете его , и это
null
,NullPointer
. Если он передается в и этоnull
,IllegalArgument
.источник
Apache Commons Lang имеет исключение NullArgumentException, которое выполняет ряд вещей, обсуждаемых здесь: оно расширяет IllegalArgumentException, а его единственный конструктор принимает имя аргумента, который должен быть ненулевым.
Хотя я чувствую, что создание чего-то вроде NullArgumentException или IllegalArgumentException более точно описывает исключительные обстоятельства, мои коллеги и я предпочли подчиниться совету Блоха по этому вопросу.
источник
Не могу согласиться с тем, что говорится. Неудача рано, неудача быстро. Довольно хорошая Исключительная мантра.
Вопрос о том, какое исключение бросить, в основном вопрос личного вкуса. На мой взгляд, IllegalArgumentException кажется более конкретным, чем использование NPE, так как он говорит мне, что проблема была в аргументе, который я передал методу, а не в значении, которое могло быть сгенерировано при выполнении метода.
Мои 2 цента
источник
На самом деле, вопрос о создании IllegalArgumentException или NullPointerException, на мой взгляд, является лишь «священной войной» для меньшинства с неполным пониманием обработки исключений в Java. В общем, правила просты и таковы:
Есть по крайней мере три веские причины против случая сопоставления всех видов нарушений ограничения аргументов с IllegalArgumentException, причем третий, вероятно, настолько серьезен, что обозначает плохой стиль практики:
(1) Программист не может с уверенностью предположить, что все случаи нарушения ограничения аргумента приводят к IllegalArgumentException, потому что подавляющее большинство стандартных классов используют это исключение, а не как корзину для мусора, если нет более конкретного доступного исключения. Попытка отобразить все случаи нарушения ограничения аргумента в IllegalArgumentException в вашем API только приводит к разочарованию программиста при использовании ваших классов, поскольку стандартные библиотеки в основном следуют различным правилам, которые нарушают ваши, и большинство ваших пользователей API также будут их использовать!
(2) Отображение исключений фактически приводит к другому типу аномалии, вызванной одиночным наследованием: все исключения Java являются классами и поэтому поддерживают только одиночное наследование. Следовательно, нет никакого способа создать исключение, которое действительно скажет и NullPointerException, и IllegalArgumentException, поскольку подклассы могут наследоваться только от одного или другого. Поэтому создание исключения IllegalArgumentException в случае нулевого аргумента усложняет пользователям API различие между проблемами, когда программа пытается программно исправить проблему, например, путем ввода значений по умолчанию в повтор вызова!
(3) Отображение фактически создает опасность маскирования ошибок: чтобы отобразить нарушения ограничения аргумента в IllegalArgumentException, вам необходимо кодировать внешнюю попытку в каждом методе, который имеет какие-либо ограниченные аргументы. Однако просто перехватить RuntimeException в этом блоке перехвата не может быть и речи, потому что это рискует отобразить документированные RuntimeException, выброшенные вашими методами libery, в IllegalArgumentException, даже если они не вызваны нарушениями ограничения аргумента. Таким образом, вы должны быть очень конкретны, но даже это усилие не защитит вас от случая, когда вы случайно отобразите недокументированное исключение времени выполнения другого API (т.е. ошибку) в IllegalArgumentException вашего API.
С другой стороны, при стандартной практике правила остаются простыми, а причины исключений остаются без масок и специфичны. Для вызывающего метода правила также просты: - если вы столкнулись с документированным исключением времени выполнения любого рода, потому что вы передали недопустимое значение, либо повторите вызов со значением по умолчанию (для этого конкретного исключения необходимы), либо исправьте свой код - если, с другой стороны, вы обнаружите исключение времени выполнения, которое не задокументировано для данного набора аргументов, отправьте отчет об ошибке создателям метода, чтобы убедиться, что их код или документация исправлены.
источник
Общепринятая практика, если использовать IllegalArgumentException (String message), чтобы объявить параметр недействительным и предоставить как можно больше подробностей ... То есть сказать, что параметры были определены как нулевые, а исключение ненулевое, вы бы что-то сделали нравится:
У вас практически нет причин неявно использовать «NullPointerException». NullPointerException - это исключение, которое выдается виртуальной машиной Java при попытке выполнить код по нулевой ссылке (например, toString () ).
источник
Создание исключения, исключающего
null
аргументы (NullPointerException
или пользовательского типа), делает автоматизированноеnull
тестирование более надежным. Это автоматизированное тестирование может быть сделано с отражением и набором значений по умолчанию, как в гуавы «сNullPointerTester
. Например,NullPointerTester
попытался бы вызвать следующий метод ...... с двумя списками аргументов:
"", null
иnull, ImmutableList.of()
. Было бы проверить, что каждый из этих вызовов бросает ожидаемыйNullPointerException
. Для этой реализации передачаnull
списка не производитNullPointerException
. Это, однако, случается,IllegalArgumentException
потомуNullPointerTester
что использует строку по умолчанию""
. ЕслиNullPointerTester
ожидает толькоNullPointerException
дляnull
значений, он ловит ошибку. Если он ожидаетIllegalArgumentException
, он пропускает это.источник
Некоторые коллекции предполагают, что
null
отклонено использованиеNullPointerException
вместоIllegalArgumentException
. Например, если вы сравниваете набор, содержащийnull
набор, который отклоняетnull
, первый набор вызоветcontainsAll
другой и поймает егоNullPointerException
- но неIllegalArgumentException
. (Я смотрю на реализациюAbstractSet.equals
.)Вы могли бы обоснованно утверждать, что использование непроверенных исключений таким способом является антипаттерном, что сравнение коллекций, которые содержат,
null
с коллекциями, которые не могут содержать,null
является вероятной ошибкой, которая действительно должна вызвать исключение, или чтоnull
добавление коллекции вообще является плохой идеей. , Тем не менее, если вы не готовы сказать, чтоequals
в таком случае должно возникать исключение, вы застряли, вспомнив, чтоNullPointerException
требуется в определенных обстоятельствах, но не в других. («IAE до NPE, кроме как после« c »...»)источник
new TreeSet<>().containsAll(Arrays.asList((Object) null));
бросаетNPE
потому чтоList
содержитnull
.В качестве субъективного вопроса это должно быть закрыто, но так как оно все еще открыто:
Это часть внутренней политики, используемой на моем предыдущем месте работы, и она работала очень хорошо. Это все из памяти, поэтому я не могу вспомнить точную формулировку. Стоит отметить, что они не использовали проверенные исключения, но это выходит за рамки вопроса. Непроверенные исключения, которые они использовали, попали в 3 основные категории.
NullPointerException: не бросать намеренно. NPE должны создаваться только виртуальной машиной при разыменовании нулевой ссылки. Все возможные усилия должны быть предприняты, чтобы гарантировать, что они никогда не будут брошены. @Nullable и @NotNull должны использоваться вместе с инструментами анализа кода, чтобы найти эти ошибки.
IllegalArgumentException: генерируется, когда аргумент функции не соответствует общедоступной документации, так что ошибка может быть идентифицирована и описана в терминах переданных аргументов. Ситуация OP попадает в эту категорию.
IllegalStateException: генерируется, когда вызывается функция и ее аргументы либо неожиданны в момент их передачи, либо несовместимы с состоянием объекта, членом которого является метод.
Например, были две внутренние версии IndexOutOfBoundsException, используемые в вещах, которые имели длину. Один подкласс IllegalStateException, используемый, если индекс был больше, чем длина. Другой подкласс IllegalArgumentException, используемый, если индекс был отрицательным. Это потому, что вы можете добавить больше объектов к объекту, и аргумент будет действительным, а отрицательное число никогда не будет действительным.
Как я уже сказал, эта система работает очень хорошо, и потребовался кто-то, чтобы объяснить, почему существует различие: «В зависимости от типа ошибки вам довольно просто понять, что делать. Даже если вы не можете понять, на самом деле из того, что пошло не так, вы можете выяснить, где отловить эту ошибку и создать дополнительную информацию для отладки. "
NullPointerException: обрабатывать случай Null или вставлять утверждение, чтобы NPE не выбрасывалось. Если вы вставите утверждение, это просто один из двух других типов. Если возможно, продолжайте отладку, как если бы утверждение было в первую очередь.
IllegalArgumentException: у вас что-то не так на вашем сайте вызова. Если передаваемые значения получены из другой функции, выясните, почему вы получаете неправильное значение. Если вы передаете один из своих аргументов, распространяете ошибку, проверяете стек вызовов, пока не найдете функцию, которая не возвращает то, что вы ожидаете.
IllegalStateException: вы не вызвали свои функции в правильном порядке. Если вы используете один из ваших аргументов, проверьте их и сгенерируйте исключение IllegalArgumentException, описывающее проблему. Затем вы можете распространять щеки к стеку, пока не найдете проблему.
В любом случае, он хотел, чтобы вы могли копировать только IllegalArgumentAssertions в стек. Вы не можете распространять IllegalStateExceptions или NullPointerExceptions в стеке, поскольку они имеют какое-то отношение к вашей функции.
источник
В общем, разработчик никогда не должен выбрасывать исключение NullPointerException. Это исключение выдается средой выполнения, когда код пытается разыменовать переменную, значение которой равно нулю. Следовательно, если ваш метод хочет явно запретить значение NULL, в отличие от того, что значение NULL приводит к возникновению исключения NullPointerException, вы должны вызвать исключение IllegalArgumentException.
источник
Я хотел выделить аргументы Null из других недопустимых аргументов, поэтому я вывел исключение из IAE с именем NullArgumentException. Даже не имея необходимости читать сообщение об исключении, я знаю, что в метод был передан нулевой аргумент, и, прочитав сообщение, я выясняю, какой аргумент был нулевым. Я все еще ловлю исключение NullArgumentException с помощью обработчика IAE, но в моих журналах я могу быстро увидеть разницу.
источник
дихотомия ... они не перекрываются? Только непересекающиеся части целого могут создавать дихотомию. Как я вижу это:
источник
NullPointerException
ничего не даст. Единственное, что может помочьIllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException
, но у нас нет множественного наследования.NullPointerException
бросается при попытке доступа к объекту с помощью ссылочной переменной, текущее значение которой равноnull
.IllegalArgumentException
бросается, когда метод получает аргумент, отформатированный не так, как ожидает метод.источник
Согласно вашему сценарию,
IllegalArgumentException
это лучший выбор, потому чтоnull
не является действительным значением для вашей собственности.источник
В идеале исключения во время выполнения не должны создаваться. Проверенное исключение (бизнес-исключение) должно быть создано для вашего сценария. Потому что, если любое из этих исключений выбрасывается и регистрируется, оно вводит разработчика в заблуждение при просмотре журналов. Вместо этого бизнес-исключения не создают такой паники и обычно игнорируются при устранении неполадок в журналах.
источник
Определения из ссылок на два вышеупомянутых исключения являются IllegalArgumentException: Брошенный, чтобы указать, что методу был передан недопустимый или неподходящий аргумент. NullPointerException: выдается, когда приложение пытается использовать значение NULL в случае, когда требуется объект.
Большая разница здесь заключается в том, что IllegalArgumentException предполагается использовать при проверке правильности аргумента метода. Предполагается, что NullPointerException будет использоваться всякий раз, когда объект «используется», когда он нулевой.
Я надеюсь, что это помогает поставить два в перспективе.
источник
Если это «сеттер» или где-то, что я получаю, чтобы член использовал позже, я склонен использовать IllegalArgumentException.
Если это то, что я собираюсь использовать (разыменование) прямо сейчас в методе, я предварительно выбрасываю исключение NullPointerException. Мне нравится это лучше, чем позволить среде выполнения делать это, потому что я могу предоставить полезное сообщение (кажется, что среда выполнения может сделать это тоже, но это напыщенная речь на другой день).
Если я переопределяю метод, я использую то, что использует переопределенный метод.
источник
Вы должны выбросить исключение IllegalArgumentException, так как для программиста станет очевидным, что он сделал что-то недопустимое. Разработчики настолько привыкли видеть, что NPE выбрасывается виртуальной машиной, что любой программист не сразу осознает свою ошибку и начнет случайно оглядываться по сторонам или, что еще хуже, обвинять ваш код в «глючности».
источник
В этом случае 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 (...) метод.
источник
Если вы решите бросить NPE и используете аргумент в своем методе, может оказаться излишним и дорогим явная проверка на нулевое значение. Я думаю, что виртуальная машина уже делает это для вас.
источник
NPE
но программисты говорятIAE
перед ВМ, если они хотят.