[java] How to use @Nullable and @Nonnull annotations more effectively?

I can see that @Nullable and @Nonnull annotations could be helpful in preventing NullPointerExceptions but they do not propagate very far.

  • The effectiveness of these annotations drop off completely after one level of indirection, so if you only add a few they don't propagate very far.
  • Since these annotations are not well enforced there is a danger of assuming a value marked with @Nonnull is not null and consequently not performing null checks.

The code below causes a parameter marked with @Nonnull to be null without raising any complaints. It throws a NullPointerException when it is run.

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?

The answer is


Since Java 8 new feature Optional you should not use @Nullable or @Notnull in your own code anymore. Take the example below:

public void printValue(@Nullable myValue) {
    if (myValue != null) {
        System.out.print(myValue);
    } else {
        System.out.print("I dont have a value");
}

It could be rewritten with:

public void printValue(Optional<String> myValue) {
    if (myValue.ifPresent) {
        System.out.print(myValue.get());
    } else {
        System.out.print("I dont have a value");
}

Using an optional forces you to check for null value. In the code above, you can only access the value by calling the get method.

Another advantage is that the code get more readable. With the addition of Java 9 ifPresentOrElse, the function could even be written as:

public void printValue(Optional<String> myValue) {
    myValue.ifPresentOrElse(
        v -> System.out.print(v),
        () -> System.out.print("I dont have a value"),
    )
}

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

As said in the "Clean Code" book, you should check your public method's parameters and also avoid checking invariants.

Another good tip is never returning null values, but using Null Object Pattern instead.


I agree that the annotations "don't propagate very far". However, I see the mistake on the programmer's side.

I understand the Nonnull annotation as documentation. The following method expresses that is requires (as a precondition) a non-null argument x.

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

The following code snippet then contains a bug. The method calls directPathToA() without enforcing that y is non-null (that is, it does not guarantee the precondition of the called method). One possibility is to add a Nonnull annotation as well to indirectPathToA() (propagating the precondition). Possibility two is to check for the nullity of y in indirectPathToA() and avoid the call to directPathToA() when y is null.

    public void indirectPathToA(Integer y){
        directPathToA(y);
    }

Other than your IDE giving you hints when you pass null to methods that expect the argument to not be null, there are further advantages:

This can help your code be more maintainable (since you do not need null checks) and less error-prone.


Compiling the original example in Eclipse at compliance 1.8 and with annotation based null analysis enabled, 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 worded in analogy to those warnings you get when mixing generified code with legacy code using raw types ("unchecked conversion"). We have the exact same situation here: method indirectPathToA() has a "legacy" signature in that it doesn't specify any null contract. Tools can easily report this, so they will chase you down all alleys where null annotations need to be propagated but aren't yet.

And when using a clever @NonNullByDefault we don't even have to say this every time.

In other words: whether or not null annotations "propagate very far" may depend on the tool you use, and on how rigorously you attend to all the warnings issued by the tool. With TYPE_USE null annotations you finally have the option to let the tool warn you about every possible NPE in your program, because nullness has become an intrisic property of the type system.


If you use Kotlin, it supports these nullability annotations in its compiler and will prevent you from passing a null to a java method that requires a non-null argument. Event though this question was originally targeted at Java, I mention this Kotlin feature because it is specifically targeted at these Java annotation and the question was "Is there a way to make these annotations more strictly enforced and/or propagate further?" and this feature does make these annotation more strictly enforced.

Java class using @NotNull annotation

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

Kotlin class calling Java class and passing null for the argument annotated with @NotNull

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

Kotlin compiler error enforcing the @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


What I do in my projects is to activate the following option in the "Constant conditions & exceptions" code inspection:
Suggest @Nullable annotation for methods that may possibly return null and report nullable values passed to non-annotated parameters Inspections

When activated, all non-annotated parameters will be treated as non-null and thus you will also see a warning on your indirect call:

clazz.indirectPathToA(null); 

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


I think this original question indirectly points to a general recommendation that run-time null-pointer check is still needed, even though @NonNull is used. Refer to the following link:

Java 8's new Type Annotations

In the above blog, it is recommended that:

Optional Type Annotations are not a substitute for runtime validation Before Type Annotations, the primary location for describing things like nullability or ranges was in the javadoc. With Type annotations, this communication comes into the bytecode in a way for compile-time verification. Your code should still perform runtime validation.


In Java I'd use Guava's Optional type. Being an actual type you get compiler guarantees about its use. It's easy to bypass it and obtain a NullPointerException, but at least the signature of the method clearly communicates what it expects as an argument or what it might return.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to annotations

How to inject a Map using the @Value Spring Annotation? intellij incorrectly saying no beans of type found for autowired repository @Autowired - No qualifying bean of type found for dependency Difference between @Before, @BeforeClass, @BeforeEach and @BeforeAll Can't find @Nullable inside javax.annotation.* Name attribute in @Entity and @Table Get rid of "The value for annotation attribute must be a constant expression" message @Value annotation type casting to Integer from String What does -> mean in Python function definitions? @Nullable annotation usage

Examples related to nullpointerexception

Filter values only if not null using lambda in Java8 Why use Optional.of over Optional.ofNullable? Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference Null pointer Exception on .setOnClickListener - java.lang.NullPointerException - setText on null object reference NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equalsIgnoreCase(java.lang.String)' on a null object reference java.lang.NullPointerException: Attempt to invoke virtual method on a null object reference Java 8 NullPointerException in Collectors.toMap NullPointerException in eclipse in Eclipse itself at PartServiceImpl.internalFixContext The server encountered an internal error that prevented it from fulfilling this request - in servlet 3.0

Examples related to nullable

Laravel Migration Change to Make a Column Nullable How to set null to a GUID property How to set null value to int in c#? Can't find @Nullable inside javax.annotation.* Check if Nullable Guid is empty in c# How to declare a type as nullable in TypeScript? Java check if boolean is null How to use @Nullable and @Nonnull annotations more effectively? Nullable property to entity field, Entity Framework through Code First The type 'string' must be a non-nullable type in order to use it as parameter T in the generic type or method 'System.Nullable<T>'

Examples related to code-standards

How to use @Nullable and @Nonnull annotations more effectively?