Перейти к основному содержимому

Использование NullAway для предотвращения исключений NullPointerException

· 3 мин. чтения

1. Обзор

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

NullAway — это инструмент сборки, который помогает нам устранять исключения NullPointerException (NPE) в нашем коде Java.

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

2. Установка

Давайте посмотрим, как установить NullAway и его зависимости. В этом примере мы собираемся настроить NullAway с помощью Gradle.

NullAway зависит от Error Prone . Поэтому мы добавим ошибочный плагин:

plugins {
id "net.ltgt.errorprone" version "1.1.1"
}

Мы также добавим четыре зависимости в разных областях: annotationProcessor , compileOnly , errorprone и errorproneJavac :

dependencies {
annotationProcessor "com.uber.nullaway:nullaway:0.7.9"
compileOnly "com.google.code.findbugs:jsr305:3.0.2"
errorprone "com.google.errorprone:error_prone_core:2.3.4"
errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
}

Наконец, мы добавим задачу Gradle, которая настраивает работу NullAway во время компиляции:

import net.ltgt.gradle.errorprone.CheckSeverity

tasks.withType(JavaCompile) {
options.errorprone {
check("NullAway", CheckSeverity.ERROR)
option("NullAway:AnnotatedPackages", "com.foreach")
}
}

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

Кроме того, задача задает проверку пакета на наличие нулевых разыменований.

Вот и все, теперь мы готовы использовать этот инструмент в нашем Java-коде.

Точно так же мы можем использовать другие системы сборки , Maven или Bazel , для интеграции инструмента.

3. Использование

Допустим, у нас есть класс Person , содержащий атрибут возраста . Кроме того, у нас есть метод getAge , который принимает экземпляр Person в качестве параметра:

Integer getAge(Person person) {
return person.getAge();
}

На данный момент мы видим, что getAge вызовет исключение NullPointerException , если person имеет значение null .

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

И давайте также скажем, что в нашем коде есть место, которое действительно передает нулевую ссылку в getAge :

Integer yearsToRetirement() {
Person p = null;
// ... p never gets set correctly...
return 65 - getAge(p);
}

Затем запуск сборки приведет к следующей ошибке:

error: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
getAge(p);

Мы можем исправить эту ошибку, добавив аннотацию @Nullable к нашему параметру:

Integer getAge(@Nullable Person person) { 
// ... same as earlier
}

Теперь, когда мы запустим сборку, мы увидим новую ошибку:

error: [NullAway] dereferenced expression person is @Nullable
return person.getAge();
^

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

Integer getAge(@Nullable Person person) {
if (person != null) {
return person.getAge();
} else {
return 0;
}
}

4. Выводы

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

Как всегда весь исходный код доступен на GitHub .