«1. Введение

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

В этом кратком руководстве мы рассмотрим вопрос о том, какое исключение генерировать, когда кто-то передает нулевой параметр одному из наших методов: IllegalArgumentException или NullPointerException.

Мы изучим тему, изучив аргументы обеих сторон.

2. IllegalArgumentException

Сначала давайте рассмотрим аргументы для создания исключения IllegalArgumentException.

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

public void processSomethingNotNull(Object myParameter) {
    if (myParameter == null) {
        throw new IllegalArgumentException("Parameter 'myParameter' cannot be null");
    }
}

Теперь давайте перейдем к аргументам в пользу исключения IllegalArgumentException.

2.1. Это то, как Javadoc говорит об использовании

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

2.2. Это соответствует ожиданиям разработчиков

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

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

2.3. Другие аргументы

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

3. NullPointerException

Далее рассмотрим аргументы для исключения NullPointerException.

Давайте создадим пример, который генерирует исключение NullPointerException:

public void processSomethingElseNotNull(Object myParameter) {
    if (myParameter == null) {
        throw new NullPointerException("Parameter 'myParameter' cannot be null");
    }
}

3.1. Это то, как Javadoc говорит об использовании этого

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

3.2. Это совместимо с API JDK

Давайте уделим немного времени тому, чтобы подумать о многих распространенных методах JDK, которые мы вызываем во время разработки. Многие из них выдают исключение NullPointerException, если мы указываем значение null. Кроме того, Objects.requireNonNull() генерирует исключение NullPointerException, если мы передаем значение null. Согласно документации Objects, он существует в основном для проверки параметров.

В дополнение к методам JDK, которые вызывают NullPointerException, мы можем найти другие примеры определенных типов исключений, выбрасываемых из методов в API коллекций. ArrayList.addAll(index, Collection) выдает исключение IndexOutOfBoundsException, если индекс выходит за пределы размера списка, и выдает исключение NullPointerException, если коллекция имеет значение null. Это два очень специфических типа исключений, а не более общий IllegalArgumentException.

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

4. Заключение

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

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

Как всегда, код примера доступен на GitHub.