Я могу видеть , что @Nullable
и @Nonnull
аннотации могут быть полезными в предотвращении NullPointerException
s , но они не распространяются очень далеко.
- Эффективность этих аннотаций полностью падает после одного уровня косвенного обращения, поэтому, если вы добавляете только несколько, они не распространяются очень далеко.
- Поскольку эти аннотации плохо соблюдаются, существует опасность предположить, что значение, отмеченное значком,
@Nonnull
не является нулевым, и, следовательно, не выполнять нулевые проверки.
Приведенный ниже код заставляет параметр, отмеченный значком, не @Nonnull
вызывать null
никаких жалоб. NullPointerException
При запуске выдает ошибку.
public class Clazz {
public static void main(String[] args){
Clazz clazz = new Clazz();
// this line raises a complaint with the IDE (IntelliJ 11)
clazz.directPathToA(null);
// this line does not
clazz.indirectPathToA(null);
}
public void indirectPathToA(Integer y){
directPathToA(y);
}
public void directPathToA(@Nonnull Integer x){
x.toString(); // do stuff to x
}
}
Есть ли способ сделать эти аннотации более строгими и / или распространяться дальше?
java
annotations
nullpointerexception
nullable
code-standards
Майк Райландер
источник
источник
@Nullable
или@Nonnull
, но если они того стоят, очень "вероятно, что они@Nonnull
при вызове@Nonnull
метода с переменной, допускающей значение NULL. Конечно, преобразование с аннотацией невозможно в Java 7, но в Java 8 будет добавлена возможность применять аннотации к использованию переменной, включая приведение типов. Так что это может стать возможным реализовать в Java 8.(@NonNull Integer) y
синтаксически возможно, но компилятору не разрешено испускать какой-либо конкретный байтовый код на основе аннотации. Для утверждений во время выполнения достаточно крошечных вспомогательных методов, как описано в bugs.eclipse.org/442103 (например,directPathToA(assertNonNull(y))
), но учтите , это только помогает быстро потерпеть неудачу. Единственный безопасный способ - выполнить фактическую нулевую проверку (плюс, надеюсь, альтернативную реализацию в ветке else).@Nonnull
и@Nullable
вы говорите, так как есть несколько похожих annoations (см этого вопроса ). Вы про аннотации в пакетеjavax.annotation
?Ответы:
Краткий ответ: я предполагаю, что эти аннотации полезны только для вашей IDE, чтобы предупредить вас о потенциально возможных ошибках нулевого указателя.
Как сказано в книге «Чистый код», вам следует проверять параметры вашего общедоступного метода, а также избегать проверки инвариантов.
Еще один хороший совет - никогда не возвращать нулевые значения, а вместо этого использовать шаблон нулевого объекта .
источник
Optional
тип вместо простогоnull
Optional
и допускающим значение NULL в этом случае состоит в том, чтоOptional
лучше сообщает, что это значение может быть намеренно пустым. Конечно, это не волшебная палочка, и во время выполнения она может выйти из строя точно так же, как переменная, допускающая значение NULL. Однако,Optional
на мой взгляд , прием API программистом лучше .Помимо того, что ваша среда IDE дает вам подсказки при переходе
null
к методам, которые ожидают, что аргумент не будет нулевым, есть и другие преимущества:Это может сделать ваш код более удобным в сопровождении (поскольку вам не нужны
null
проверки) и менее подверженным ошибкам.источник
assert
. Я считаю ,@Nullable
и@Nonnull
быть полезными идеями, но я хотел бы больше силы за ними, а не с нами гипотезой о том, что один может делать с ними, что до сих пор оставляет возможность ничего не делать с ними.Я думаю, что этот исходный вопрос косвенно указывает на общую рекомендацию о том, что проверка нулевого указателя во время выполнения по-прежнему необходима, даже если используется @NonNull. Перейдите по следующей ссылке:
Новые аннотации типов в Java 8
В указанном выше блоге рекомендуется:
источник
При компиляции исходного примера в Eclipse в соответствии с требованиями 1.8 и с включенным нулевым анализом на основе аннотаций мы получаем следующее предупреждение:
directPathToA(y); ^ Null type safety (type annotations): The expression of type 'Integer' needs unchecked conversion to conform to '@NonNull Integer'
Это предупреждение сформулировано аналогично тем предупреждениям, которые вы получаете при смешивании обобщенного кода с устаревшим кодом с использованием необработанных типов («неконтролируемое преобразование»). У нас здесь точно такая же ситуация: у метода
indirectPathToA()
есть "устаревшая" подпись, так как он не определяет никакого нулевого контракта. Инструменты могут легко сообщить об этом, поэтому они будут преследовать вас по всем переулкам, где нулевые аннотации нужно распространять, но еще не сделано.И при использовании умного
@NonNullByDefault
даже не нужно говорить это каждый раз.Другими словами: «распространяются ли нулевые аннотации очень далеко», может зависеть от используемого вами инструмента и от того, насколько строго вы выполняете все предупреждения, выдаваемые этим инструментом. С нулевыми аннотациями TYPE_USE у вас, наконец, есть возможность позволить инструменту предупреждать вас обо всех возможных NPE в вашей программе, потому что пустота стала интричным свойством системы типов.
источник
Я согласен с тем, что аннотации «далеко не распространяются». Однако я вижу ошибку со стороны программиста.
Я понимаю
Nonnull
аннотацию как документацию. Следующий метод выражает необходимость (в качестве предварительного условия) ненулевого аргументаx
.public void directPathToA(@Nonnull Integer x){ x.toString(); // do stuff to x }
Следующий фрагмент кода содержит ошибку. Метод вызывает
directPathToA()
без принуждения, которое неy
равно NULL (то есть, это не гарантирует предварительное условие вызываемого метода). Одна из возможностей - добавитьNonnull
аннотацию кindirectPathToA()
(распространяя предварительное условие). Вторая возможность - проверить нулевое значениеy
inindirectPathToA()
и избежать вызоваdirectPathToA()
wheny
is null.public void indirectPathToA(Integer y){ directPathToA(y); }
источник
@Nonnull
что нужно,indirectPathToA(@Nonnull Integer y)
- это ИМХО плохая практика: вам нужно будет поддерживать распространение в полном стеке вызовов (поэтому, если вы добавитеnull
проверкуdirectPathToA()
, вам нужно будет заменить@Nonnull
на@Nullable
в полном стеке вызовов). Для больших приложений это потребует огромных усилий.Если вы используете Kotlin, он поддерживает эти аннотации, допускающие значение NULL, в своем компиляторе и не позволит вам передать значение NULL в метод java, который требует аргумента, отличного от NULL. Событие, хотя этот вопрос изначально был нацелен на Java, я упоминаю эту функцию Kotlin, потому что она специально нацелена на эти аннотации Java, и вопрос звучал так: «Есть ли способ сделать эти аннотации более строгими и / или распространяться дальше?» и эта функция делает эти аннотации более строгими .
Класс Java с использованием
@NotNull
аннотацииpublic class MyJavaClazz { public void foo(@NotNull String myString) { // will result in an NPE if myString is null myString.hashCode(); } }
Класс Kotlin вызывает класс Java и передает значение null для аргумента, аннотированного с помощью @NotNull
class MyKotlinClazz { fun foo() { MyJavaClazz().foo(null) } }
Ошибка компилятора Kotlin при применении
@NotNull
аннотации.Error:(5, 27) Kotlin: Null can not be a value of a non-null type String
см. http://kotlinlang.org/docs/reference/java-interop.html#nullability-annotations
источник
myString.hashCode()
прежнему будет вызывать NPE, даже если@NotNull
он не добавлен в параметр. Так что более конкретно о его добавлении?Что я делаю в своих проектах, так это активирую следующий параметр в проверке кода «Постоянные условия и исключения»:
предлагаю аннотацию @Nullable для методов, которые могут возвращать значение NULL, и сообщать обнуляемые значения, переданные параметрам без аннотации
При активации все неаннотированные параметры будут обрабатываться как ненулевые, и поэтому вы также увидите предупреждение при косвенном вызове:
clazz.indirectPathToA(null);
Для еще более сильных проверок может оказаться хорошим выбором Checker Framework (см. Этот хороший учебник .
Примечание : я еще не использовал его, и могут возникнуть проблемы с компилятором Jack: см. Этот отчет об ошибке)
источник
В Java я бы использовал дополнительный тип Guava . Будучи актуальным типом, вы получаете гарантии компилятора относительно его использования. Его легко обойти и получить
NullPointerException
, но по крайней мере сигнатура метода четко сообщает, что он ожидает в качестве аргумента или что он может вернуть.источник
java.util.Optional
вместо класса Guava. См. Примечания / сравнение Guava для получения подробной информации о различиях.Поскольку новая функция Java 8 является необязательной, вам больше не следует использовать @Nullable или @Notnull в своем собственном коде . Возьмите пример ниже:
public void printValue(@Nullable myValue) { if (myValue != null) { System.out.print(myValue); } else { System.out.print("I dont have a value"); }
Его можно переписать с помощью:
public void printValue(Optional<String> myValue) { if (myValue.ifPresent) { System.out.print(myValue.get()); } else { System.out.print("I dont have a value"); }
Использование необязательного параметра заставляет вас проверять нулевое значение . В приведенном выше коде вы можете получить доступ к значению, только вызвав
get
метод.Еще одно преимущество - код становится более читабельным . С добавлением Java 9 ifPresentOrElse функцию можно было бы даже записать как:
public void printValue(Optional<String> myValue) { myValue.ifPresentOrElse( v -> System.out.print(v), () -> System.out.print("I dont have a value"), ) }
источник
Optional
этом по-прежнему существует множество библиотек и фреймворков, которые используют эти аннотации, поэтому невозможно обновить / заменить все ваши зависимости версиями, обновленными для использования Optionals.Optional
Однако может помочь в ситуациях, когда вы используете null в своем собственном коде.