Стиль конструктора Java: параметры проверки не равны NULL - PullRequest
65 голосов
/ 08 июня 2010

Каковы лучшие практики, если у вас есть класс, который принимает некоторые параметры, но ни один из них не может быть null?

Следующее очевидно, но исключение немного не определено:

public class SomeClass
{
     public SomeClass(Object one, Object two)
     {
        if (one == null || two == null)
        {
            throw new IllegalArgumentException("Parameters can't be null");
        }
        //...
     }
}

Здесь исключения позволяют вам узнать, какой параметр имеет значение null, но конструктор теперь довольно уродлив:

public class SomeClass
{
     public SomeClass(Object one, Object two)
     {
        if (one == null)
        {
            throw new IllegalArgumentException("one can't be null");
        }           
        if (two == null)
        {
            throw new IllegalArgumentException("two can't be null");
        }
        //...
  }

Здесь конструктор более аккуратный, но теперь код конструктора неконструктор:

public class SomeClass
{
     public SomeClass(Object one, Object two)
     {
        setOne(one);
        setTwo(two);
     }


     public void setOne(Object one)
     {
        if (one == null)
        {
            throw new IllegalArgumentException("one can't be null");
        }           
        //...
     }

     public void setTwo(Object two)
     {
        if (two == null)
        {
            throw new IllegalArgumentException("two can't be null");
        }
        //...
     }
  }

Какой из этих стилей лучше?

Или есть альтернатива, которая более широко принята?

Ответы [ 10 ]

87 голосов
/ 08 июня 2010

Второй или третий.

Потому что он сообщает пользователю вашего API, что именно пошло не так.

Для меньшей детализации используйте Validate.notNull(obj, message) от commons-lang.Таким образом, ваш конструктор будет выглядеть так:

public SomeClass(Object one, Object two) {
    Validate.notNull(one, "one can't be null");
    Validate.notNull(two, "two can't be null");
    ...
}

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

36 голосов
/ 08 июня 2010

Вы можете использовать одну из множества библиотек, разработанных для облегчения проверки предварительных условий.Многие коды в Google 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, то есть широко в Гуаве .Затем вы можете написать:

 import static com.google.common.base.Preconditions.checkNotNull;
 //...

 public SomeClass(Object one, Object two) {
     this.one = checkNotNull(one);
     this.two = checkNotNull(two, "two can't be null!");
     //...
 }

Большинство методов перегружены или не принимают сообщение об ошибке, фиксированное сообщение об ошибке или шаблонное сообщение об ошибке с переменными.


Вкл IllegalArgumentException vs NullPointerException

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

Вот цитата из Effective JavaИздание 2-е: Пункт 60: Поддерживайте использование стандартных исключений :

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

A NullPointerException не зарезервировано только для случаев, когдаВы получаете доступ к членам null ссылки;довольно стандартно бросать их, когда аргумент равен null, когда это недопустимое значение.

System.out.println("some string".split(null));
// throws NullPointerException
33 голосов
/ 18 января 2016

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

Java 7 добавил java.lang.Objects.requireNonNull() к API, который может использовать каждый. Таким образом, проверка всех аргументов для нуля сводится к короткому списку вроде:

this.arg1 = Objects.requireNonNull(arg1, "arg1 must not be null");
this.arg2 = Objects.requireNonNull(arg2, "arg2 must not be null");

Примечания:

  • убедитесь, что не изменили два аргумента - второй - это сообщение, которое будет использоваться для NPE, которое выбрасывается, если первый аргумент равен нулю (если вы перевернете их, ну тогда ваш чек никогда не подведет)
  • еще одна лучшая практика: если возможно, сделайте все ученики окончательными (чтобы вы могли быть уверены: когда какой-либо объект был успешно создан, все его члены не равны нулю и они не изменятся со временем)
4 голосов
/ 08 июня 2010

У меня был бы служебный метод:

 public static <T> T checkNull(String message, T object) {
     if(object == null) {
       throw new NullPointerException(message);
     }
     return object;
  }

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

 public Constructor(Object param) {
     this.param = checkNull("Param not allowed to be null", param);
 }

РЕДАКТИРОВАТЬ: Что касается предложений по использованию сторонней библиотеки, в частности, Предварительные условия Google делают вышеупомянутое даже лучше моего кода. Однако, если это единственные причины для включения библиотеки в ваш проект, я бы колебался. Метод слишком прост.

3 голосов
/ 08 июня 2010

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

Из блога Misko Hevery по тестируемости: Утверждать или не утверждать

2 голосов
/ 15 апреля 2015

Сравнение способов проверки предварительных условий в Java - Guava против Apache Commons и Spring Framework против простых Java-утверждений-candies.com/blog-1/comparison-of-ways-to-check-preconditions-in-java

1 голос
/ 08 июня 2010

Аннотации для статического анализа также полезны как в дополнение к проверкам во время выполнения, так и вместо них.

FindBugs, например, предоставляет аннотацию @NonNull.

public SomeClass (@NonNull Object one, @NonNull Object two) {

1 голос
/ 08 июня 2010

Альтернативой выбрасыванию непроверенного исключения будет использование assert. В противном случае я выброшу проверенные исключения, чтобы вызывающий объект осознавал тот факт, что конструктор не будет работать с недопустимыми значениями.

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

Обратите внимание, что второй и третий примеры не могут правильно сообщить, что оба параметра были нулевыми.

Кстати - я голосую за вариант (1):

if (one == null || two == null) {
    throw new IllegalArgumentException(
      String.format("Parameters can't be null: one=%s, two=%s", one, two));
}
0 голосов
/ 31 марта 2011

Я предполагаю, что вы говорите о встроенном assert в Java. На мой взгляд, это не очень хорошая идея, чтобы использовать его. Поскольку его можно включить / выключить с помощью параметров командной строки. Поэтому некоторые говорят, что это приемлемо для использования только в частных методах.

Мои наставники говорят мне не изобретать колесо! Их совет - использовать библиотеки. Они (вероятно) хорошо разработаны и проверены. Конечно, вы должны убедиться, что вы взяли библиотеку хорошего качества.

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

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

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

Кстати: в зависимости от ваших целей я бы выбрал 2 или 3, используя одну из упомянутых выше библиотек ...

0 голосов
/ 08 июня 2010

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

...