Сообщение об ошибке проверки Null, поскольку оно равно null или было null

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

Мы склонны использовать что-то вроде этого

public User getUser(String username){
   if (username == null){
     throw new IllegalArgumentException("username is null");   
   }
   // ...
}

Что лучше: «равно нулю» или «было равно нулю» и почему?

Для меня "нулевой" кажется более естественным.


person Timo Westkämper    schedule 11.06.2010    source источник
comment
Вот почему мне нравятся константные ссылки в C++.   -  person Viktor Sehr    schedule 11.06.2010
comment
@ Виктор Сер Ага. Таким образом, есть причина, по которой в C++ нравятся ссылки на const, — это избегать аргументов is vs was.   -  person Tom Hawtin - tackline    schedule 11.06.2010
comment
Меня немного забавляет, что вопрос о том, есть или был, кажется достаточно важным для любого, кто даже может его задать. Я приветствую то, что вы хотите писать лучший код, какой только можете, но при всем уважении, возможно, пришло время пересмотреть, какие проблемы с качеством кода действительно имеют значение.   -  person Kevin Bourrillion    schedule 11.06.2010
comment
@kevin-bourrillion, я, конечно, понимаю, что есть дела поважнее, просто хотел услышать мнения по этому поводу. возможно, пришло время пересмотреть, какие проблемы с качеством кода действительно имеют значение. Это будет мой следующий вопрос;)   -  person Timo Westkämper    schedule 11.06.2010


Ответы (4)


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

То есть вместо "username is null" скажите "username should not be null".


Об использовании библиотек для проверки предварительных условий

В качестве подсказки вы можете использовать одну из множества библиотек, предназначенных для облегчения проверки предварительных условий. Многие коды в Guava используют com.google.common.base.Preconditions

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

 if (count <= 0) {
   throw new IllegalArgumentException("must be positive: " + count);
 }

заменить на более компактный

 checkArgument(count > 0, "must be positive: %s", count);

Более важным здесь является то, что он имеет checkNotNull, что позволяет просто написать:

  checkNotNull(username, "username should not be null");

Обратите внимание, как естественно выглядит приведенный выше код с подробным сообщением, в котором явно указывается требование, которое было нарушено.

Альтернатива констатации фактов более неудобна:

 // Awkward!
 checkArgument(count > 0, "is negative or zero: %s", count);
 checkNotNull(username, "username is null");

Более того, это также потенциально менее полезно, поскольку клиент может уже знать об этом факте, а исключение не поможет ему понять, каковы фактические требования.


On IllegalArgumentException vs NullPointerException

В то время как ваш исходный код выдает IllegalArgumentException для null аргументов, вместо этого Preconditions.checkNotNull в Guava выдает NullPointerException.

Это соответствует правилам, установленным API:

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

Кроме того, вот цитата из Effective Java 2nd Edition: пункт 60. Отдавайте предпочтение использованию стандартных исключений:

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

person polygenelubricants    schedule 11.06.2010
comment
@polygenelubricants, я не уверен, согласен ли я с вопросом типа исключения, но первая часть вашего ответа действительно хороша. Спасибо! - person Timo Westkämper; 11.06.2010
comment
диктата соглашения недостаточно, использование IllegalArgumentException для явных проверок и NPE для чего-то, что делает система, имеет для меня больше смысла, но приятно знать, что есть и другие мнения;) - person Timo Westkämper; 11.06.2010
comment
Дебаты IAE и NPE о нулевых аргументах устарели. В IAE много смысла, но за NPE стоит многолетняя условность. Для Preconditions.checkNotNull нам пришлось выбрать одно или другое, и мы выбрали NPE. Одним из преимуществ NPE является то, что если ваш метод меняется с неявной проверки (просто разыменование) на явную проверку или наоборот, тип исключения не меняется. Некоторые люди считают, что вы всегда должны тщательно проверять все, даже если одно и то же исключение будет выброшено двумя строками ниже, но я считаю это пустой тратой времени и места. - person Kevin Bourrillion; 11.06.2010
comment
(продолжение) самое подходящее место, чтобы все подробно и подробно рассказать об этом, — в ваших модульных тестах, а не в коде реализации. - person Kevin Bourrillion; 11.06.2010
comment
@ Кевин, не могли бы вы подробнее объяснить, почему вы выбрали NPE? Также я хотел бы знать, почему были введены эти Preconditions.check *? Чтобы изменить три строки, выполняющие проверку + бросок, на одну строку? - person Thorbjørn Ravn Andersen; 02.12.2010
comment
вопрос 1: больше нечего объяснять. Как я уже сказал, за этим стояло многолетнее соглашение, и наша цель состояла не в том, чтобы попытаться нарушить это соглашение, а в том, чтобы упростить то, что наши пользователи уже делали. вопрос 2: да, это об этом. - person Kevin Bourrillion; 07.12.2010

равно нулю, так как аргумент по-прежнему равен нулю..

Однако почему бы просто не сгенерировать исключение NullPointerException без сообщения?

person ThiefMaster    schedule 11.06.2010
comment
бросать NullPointerException без сообщения нехорошо, так как его непросто отделить от случайного NullPointerException - person Timo Westkämper; 11.06.2010
comment
Создание исключения без сообщения часто (если не всегда) является плохой идеей. Одно только исключение редко бывает достаточно информативным, чтобы понять, что на самом деле пошло не так. - person hudolejev; 11.06.2010
comment
@Timo Westkämper на 1 секунду быстрее (: - person hudolejev; 11.06.2010
comment
А еще лучше: сгенерируйте NPE с именем аргумента в качестве сообщения. Не нужно многословия, но указание имени аргумента является полезной информацией. - person Konrad Rudolph; 11.06.2010
comment
@Timo Это NPE. Конечно случайно! Если вы считаете, что добавление имени аргумента важно, то ваши методы явно имеют слишком много параметров и вы используете слишком много значений NULL. - person Tom Hawtin - tackline; 11.06.2010
comment
Создание исключения нулевого указателя без сообщения означает, что программист ДОЛЖЕН фактически просмотреть исходный код, чтобы определить, что вызвало исключение, основываясь исключительно на номере строки. Вы как программист знаете что не так - почему бы и не сказать? - person Thorbjørn Ravn Andersen; 11.06.2010
comment
@tom-hawtin-tackline, зачем писать нулевые проверки, которые выдают NPE без сообщения, они выглядят так же, как NPE из системы. Когда я выписываю чеки, я хочу предоставить больше информации. - person Timo Westkämper; 11.06.2010
comment
@Timo - если вам станет легче добавить сообщение, сделайте это. Однако многие опытные Java-разработчики считают, что это не добавляет реальной ценности. Разработчику в любом случае нужно будет посмотреть исходный код. - person Stephen C; 11.06.2010
comment
Вы должны учитывать, как часто эти сообщения не синхронизируются с фактическими именами параметров из-за рефакторинга. Я также видел случаи, когда указанное имя параметра даже не соответствует имени параметра, используемому в интерфейсе, через который клиент получает доступ к методу, так что это просто сбивает с толку. В основном я твердо верю, что по крайней мере в 95% случаев это сообщение не поможет программисту-отладчику. Он посмотрит на код; если бы было несколько аргументов, это могло бы быть, он посмотрит на строку трассировки стека... в целом с ним все будет в порядке. - person Kevin Bourrillion; 11.06.2010

я бы предложил сказать

  if (userName == null) {
     throw new IllegalArgumentException("username == null");
   }

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

person Thorbjørn Ravn Andersen    schedule 11.06.2010
comment
Интересный подход. Спасибо, что поделился! Но исправьте случай для имени пользователя. (имя пользователя != имя пользователя) - person Timo Westkämper; 11.06.2010
comment
Надеюсь, это незначительная деталь — если, конечно, у вас нет в качестве параметров и имени пользователя, и имени пользователя. :) - person Thorbjørn Ravn Andersen; 11.06.2010
comment
Ну да, но это выглядит запутанно. Но, возможно, это также лучшая практика, о которой я не знаю;) - person Timo Westkämper; 11.06.2010

Я был бы склонен написать это:

public User getUser(String username) {
   if (username.length() == 0) {
       throw new IllegalArgumentException("username is empty");   
   }
   // ...
}

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

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

public User getUser(String username){
   if (username == null){
       throw new NullPointerException("username is null");   
   }
   if (username.length() == 0) {
       throw new IllegalArgumentException("username is empty");   
   }
   // ...
}

Зачем использовать NPE здесь? Поскольку NPE почти всегда указывает на другую проблему, чем на другие типы ошибок проверки аргументов; например поле или ячейка массива, которые не были инициализированы, или «необязательное» значение, которое не обрабатывается должным образом.

Наконец к вопросу:

Что лучше: "is null" или "was null" и почему?

Это вопрос мнения, но я бы написал "is null".

  • Потому что сообщение сообщает о состоянии, когда было выдано исключение.
  • Потому что так принято делать.
person Stephen C    schedule 11.06.2010