如何更有效地使用@Nullable和@Nonnull注释
我可以看到@Nullable
和@Nonnull
注释有助于防止NullPointerException
但是它们不会传播很远。
- 这些注释的有效性在一层间接后完全消失,所以如果只添加一些注释,它们就不会传播很远。
- 由于这些注释没有被很好地执行,所以存在假设用
@Nonnull
标记的值不为空并且因此不执行空检查的危险。
下面的代码会使用@Nonnull
标记的参数为null
而不会引发任何投诉。 它在运行时抛出一个NullPointerException
exception。
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 } }
有没有办法使这些注释更加严格执行和/或进一步传播?
简短的回答:我猜这些注释只对你的IDE有用,提醒你潜在的空指针错误。
正如“清洁代码”一书所述,您应该检查公开方法的参数,并避免检查不variables。
另一个好的提示是永远不会返回空值,而是使用空对象模式 。
在你的IDE旁边,提示你在预期不为null
地方传递null,你还有其他优点:
- 静态代码分析工具可以testing相同的IDE(例如FindBugs)。
- 你可以用AOP来检查这个断言。
所以它可以帮助创build更易维护的代码(不需要null
检查)并且不太容易出错。
在符合1.8的Eclipse中编译原始示例,并且启用了基于注解的空分析,我们得到以下警告:
directPathToA(y); ^ Null type safety (type annotations): The expression of type 'Integer' needs unchecked conversion to conform to '@NonNull Integer'
这个警告类似于使用原始types(“unchecked conversion”)将遗传代码与遗留代码混合时得到的警告。 我们在这里有完全相同的情况:方法indirectPathToA()
具有“遗留”签名,因为它没有指定任何空合约。 工具可以很容易地报告这一点,所以他们会追逐你所有的空白注释需要传播,但尚未。
而当使用聪明的@NonNullByDefault
我们甚至不必每次都这样说。
换句话说,空注释是否“传播得很远”可能取决于您使用的工具以及您是否严格遵守工具发出的所有警告。 使用TYPE_USE空注释,您终于可以select让工具向您提供有关程序中每个可能的NPE的警告,因为nullness已成为types系统的一种内在属性。
我同意注释“不会传播很远”。 但是,我看到程序员方面的错误。
我将Nonnull
注解理解为文档。 以下方法表示需要(作为先决条件)非空参数x
。
public void directPathToA(@Nonnull Integer x){ x.toString(); // do stuff to x }
下面的代码片段包含一个错误。 该方法调用directPathToA()
而不强制y
不为空(也就是说,它不保证被调用方法的先决条件)。 一种可能性是添加Nonnull
注释以及indirectPathToA()
(传播前提条件)。 可能性二是检查indirectPathToA()
中y
的无效性,并避免在y
为空时调用directPathToA()
。
public void indirectPathToA(Integer y){ directPathToA(y); }
我认为这个原始的问题间接指出了一个普遍的build议,即使使用了@NonNull,仍然需要运行时空指针检查。 请参阅以下链接:
Java 8新的Type Annotations
在上面的博客中,build议:
可选types注解不能替代运行时validation在“types注释”之前,用于描述可空性或范围的主要位置在javadoc中。 通过Type注释,这个通信以编译时validation的方式进入字节码。 你的代码仍然应该执行运行时validation。
我在项目中做的是在“恒定条件和例外”代码检查中激活以下选项:
为可能返回空值的方法build议@Nullable注释,并报告传递给未注释参数的可空值
激活时,所有未注释的参数将被视为非空值,因此您也将在间接调用中看到警告:
clazz.indirectPathToA(null);
为了更强大的检查,Checker框架可能是一个不错的select(请参阅这个很好的教程 。
注意 :我还没有使用过,并且Jack编译器可能有问题:请参阅此bugreport
在Java中我会使用Guava的可选types 。 作为一个实际的types,你得到编译器保证它的使用。 很容易绕过它,并获得一个NullPointerException
,但至less该方法的签名清楚地传达了它所期望的作为参数或可能返回的内容。
如果您使用Kotlin,它将在编译器中支持这些可空性注释,并且会阻止您将空值传递给需要非空参数的java方法。 虽然这个问题的事件最初是针对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类并为用@NotNull注释的parameter passingnull
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