Подтвердить что ты не робот

IllegalArgumentException или NullPointerException для нулевого параметра?

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

Например, Javadoc для Map.containsKey указывает:

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

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

Образец идет:

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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

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

Мои 2 цента

Ответ 11

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

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

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

Ответ 12

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

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

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

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

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

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

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

Ответ 13

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

Ответ 14

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

Ответ 15

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

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

Ответ 16

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

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

Ответ 17

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

Ответ 18

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

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

Ответ 19

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

Ответ 20

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

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

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

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

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

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

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

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

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

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

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

Ответ 21

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

Ответ 22

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

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

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

Ответ 23

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

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

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

Ответ 24

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

Ответ 25

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

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

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

Ответ 26

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