Различают статический анализ и анализ времени выполнения. Используйте статический анализ для внутренних вещей и анализ времени выполнения для открытых границ вашего кода.
Для вещей, которые не должны быть нулевыми:
Проверка во время выполнения: используйте «if (x == null) ...» (нулевая зависимость) или @ javax.validation.NotNull (с проверкой бина) или @ lombok.NonNull (просто и просто) или guavas Preconditions.checkNotNull (...)
- Использовать дополнительно для типов возвращаемых методов (только). Либо Java8, либо Гуава.
Статическая проверка: используйте аннотацию @NonNull
- Там, где он подходит, используйте аннотации @ ... NonnullByDefault на уровне класса или пакета. Создайте эти аннотации самостоятельно (примеры легко найти).
- Иначе, используйте @ ... CheckForNull при возврате метода, чтобы избежать NPE
Это должно дать наилучший результат: предупреждения в IDE, ошибки Findbugs и checkerfrawork, значимые исключения во время выполнения.
Не ожидайте, что статические проверки будут зрелыми, их именование не стандартизировано, и разные библиотеки и IDE обрабатывают их по-разному, игнорируя их. Классы JSR305 javax.annotations. * Выглядят как стандартные, но это не так, и они вызывают разделение пакетов с Java9 +.
Некоторые примечания к пояснениям:
- аннотации Findbugs / spotbugs / jsr305 с пакетом javax.validation. * Конфликт с другими модулями в Java9 +, возможно также нарушающий лицензию Oracle
- Примечания к Spotbugs по-прежнему зависят от комментариев jsr305 / findbugs во время компиляции (на момент написания https://github.com/spotbugs/spotbugs/issues/421)
- jetbrains @NotNull имя конфликтует с @ javax.validation.NotNull.
- аннотации jetbrains, eclipse или checkersfrawork для статической проверки имеют преимущество перед javax.annotations в том, что они не конфликтуют с другими модулями в Java9 и выше
- @javax.annotations.Nullable не означает для Findbugs / Spotbugs то, что вы (или ваша IDE) думаете, что это значит. Findbugs проигнорируют это (на участниках). Грустно, но верно (https://sourceforge.net/p/findbugs/bugs/1181)
- Для статической проверки вне IDE существует 2 бесплатных инструмента: Spotbugs (ранее Findbugs) и checkersframework.
- У библиотеки Eclipse есть @NonNullByDefault, у jsr305 есть только @ParametersAreNonnullByDefault. Это просто удобные обертки, применяющие базовые аннотации ко всему в пакете (или классе), вы можете легко создавать свои собственные. Это может быть использовано на упаковке. Это может конфликтовать с сгенерированным кодом (например, lombok).
- Аннотации Eclipse jdt не применимы к возвращениям статического метода и некоторым другим случаям
- Следует избегать использования lombok в качестве экспортированной зависимости для библиотек, которыми вы делитесь с другими людьми: чем меньше транзитивных зависимостей, тем лучше
- Использование инфраструктуры проверки Bean является мощным, но требует больших накладных расходов, так что это излишне, просто чтобы избежать ручной проверки нуля.
- Использование Optional для полей и параметров метода является спорным (статьи об этом легко найти)
- Пустые аннотации Android являются частью библиотеки поддержки Android, они поставляются с множеством других классов и не очень хорошо работают с другими аннотациями / инструментами
До Java9 это моя рекомендация:
// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;
// file: PublicApi
package example;
public class PublicApi {
/**
* @param firstname MUST NOT be null
* @param lastname MUST NOT be null
*/
public Person createPerson(
// Spotbugs ignores the param annotations, but IDEs will show problems
@Nullable String firstname, // Users might send null
@Nullable String lastname // Users might send null
) {
if (firstname == null) throw new IllagalArgumentException(...);
if (lastname == null) throw new IllagalArgumentException(...);
return doCreatePerson(fistname, lastname, nickname);
}
@NonNull // Spotbugs checks that method cannot return null
private Person doCreatePerson(
String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
String lastname,
@Nullable String nickname // tell Spotbugs null is ok
) {
return new Person(firstname, lastname, nickname);
}
@CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
private Person getNickname(
String firstname,
String lastname) {
return NICKNAMES.get(firstname + ':' + lastname);
}
}
Обратите внимание, что нет способа заставить Spotbugs выдавать предупреждение при разыменовке параметра метода NULL (на момент написания, версия 3.1 Spotbugs). Может быть, это можно сделать с помощью контрольной рамки.