How to use @Nullable and @Nonnull annotations effectively?

I see that the @Nullable and @Nonnull can be useful in preventing a NullPointerException , but they do not propagate very far.

  • The effectiveness of these annotations completely disappears after one level of indirection, so if you add only a few, they do not spread very far.
  • Since these annotations are not respected, there is a danger that the value marked with @Nonnull is not null and therefore does not perform null checks.

In the code below, the parameter marked with @Nonnull will be null without causing any complaints. It NullPointerException at startup.

 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 } } 

Is there a way to make these annotations more strictly enforced and / or propagate further?

+61
java nullpointerexception nullable annotations code-standards
Nov 20 '12 at 23:48
source share
8 answers

Short answer: I think these annotations are only useful for your IDE to warn you of possible null pointer errors.

As stated in the book Clean Code, you should check your parameters for the public method, and also avoid checking invariants.

Another good tip is never returning null values, but instead uses a null object pattern .

+39
Nov 21
source share

Besides the IDE giving you hints that you are passing null where it is not expected to be null, you will get the following benefits:

  • Static code analysis tools can test the same as your IDE (e.g. FindBugs).
  • You can AOP us to check these statements.

Thus, it can help to create code that is more convenient to maintain (you do not need null checks) and are less prone to errors.

+14
Nov 21 '12 at 8:57
source share

Having compiled the original example in Eclipse in accordance with 1.8 and including annotation-based null analysis, we get this warning:

  directPathToA(y); ^ Null type safety (type annotations): The expression of type 'Integer' needs unchecked conversion to conform to '@NonNull Integer' 

This warning is similar to the warnings you receive when mixing generated code with legacy code using raw types (“unchecked conversion”). Here we have the same situation: the indirectPathToA() method has an "obsolete" signature, in which it does not indicate a single null contract. Tools can easily report this, so they will chase you along all the alleys where you need to exchange null annotations, but not yet.

And when using smart @NonNullByDefault we don’t even have to talk about it every time.

In other words: whether or not null annotations can “spread very far” depends on the tool you use and on how closely you follow all warnings issued by the tool. With TYPE_USE null annotations , you finally have the option of letting the tool warn you about every possible NPE in your program, because nullness becomes an integral property of the type system.

+11
Sep 18 '15 at 22:06
source share

I agree that the annotations "do not extend very far." However, I see an error on the side of the programmer.

I understand Nonnull annotation as documentation. The following method expresses that a non-empty argument x is required for an (optional condition).

  public void directPathToA(@Nonnull Integer x){ x.toString(); // do stuff to x } 

The following code fragment then contains an error. The method calls directPathToA() , without applying that y not null (that is, it does not guarantee the precondition of the called method). One possibility is to add the Nonnull annotation as well as to indirectPathToA() (by propagating the precondition). The second option is to check the invalidity of y in indirectPathToA() and avoid calling directPathToA() when y is null.

  public void indirectPathToA(Integer y){ directPathToA(y); } 
+6
Sep 01 '15 at 6:33
source share

I think this original question indirectly points to a general recommendation that checking for a null pointer at runtime is still necessary, although @NonNull is used. See the following link:

New Java 8 Type Annotations

The blog above recommends:

Optional type Annotations do not replace runtime checking Before an annotation type, the main place to describe things like nullability or ranges in javadoc. With type annotations, this association is included in the bytecode in the compilation method of verification. Your code should still perform a validation check.

+5
Jun 22 '16 at 16:37
source share

What I do in my projects is to activate the following option in the code check "Constant conditions and exceptions":
Suggest @Nullable annotation for methods that can return null values ​​and report null values ​​passed to non-annotated parameters Checks

Upon activation, all non-annotated parameters will be treated as non-zero, and you will also see a warning about your indirect call:

 clazz.indirectPathToA(null); 

For even stronger checks, the Checker Framework may be a good choice (see this beautiful tutorial .
Note I have not used this yet, and there may be problems with the Jack compiler: see this bugreport

+4
Jan 16 '17 at 15:25
source share

In Java, I would use the Guava Optional Type . Being a real type, you get compiler guarantees about its use. It's easy to get around it and get a NullPointerException , but at least the method signature clearly tells you what it expects as an argument or what it can return.

+3
Nov 21
source share

If you use Kotlin, it supports these nullable annotations in its compiler and will not allow you to pass null to a java method that requires a non-empty argument. The event, although this question was originally Java-oriented, I mention this Kotlin function because it specifically targets these Java annotations , and the question was: "Is there a way to make these annotations more strictly enforced and / or propagated further?" and this feature makes these annotations more strictly enforced .

Java class using @NotNull annotations

 public class MyJavaClazz { public void foo(@NotNull String myString) { // will result in an NPE if myString is null myString.hashCode(); } } 

The Kotlin class calls the Java class and passes a null value for the argument annotated with @NotNull

 class MyKotlinClazz { fun foo() { MyJavaClazz().foo(null) } } 

Kotlin compiler error using @NotNull annotation.

 Error:(5, 27) Kotlin: Null can not be a value of a non-null type String 

see: http://kotlinlang.org/docs/reference/java-interop.html#nullability-annotations

0
Sep 19 '17 at 1:52 on
source share



All Articles