Annotation Interface NonNull


@Documented @Target(TYPE_USE) @Retention(RUNTIME) public @interface NonNull
Indicates that the annotated type usage (commonly a parameter type or return type) is considered to exclude null as a value; rarely needed within null-marked code.

This annotation serves two primary purposes:

  • To mark any sporadic non-null type usages inside a scope that is not ready to be fully NullMarked yet.
  • To perform a non-null projection of a type variable, explained below.

For a comprehensive introduction to JSpecify, please see jspecify.org.

Warning: These annotations are under development, and any aspect of their naming, locations, or design is subject to change until the JSpecify 1.0 release. Moreover, supporting analysis tools will be tracking the changes on varying schedules. Releasing a library using these annotations in its API is strongly discouraged at this time.

Non-null projection

In the following example, MyOptional's type parameter T accepts only non-null type arguments, but MyList's type parameter E will accept either a non-null or nullable type argument.


 // All the below is null-marked code

 class MyOptional<T> { … }

 interface MyList<E extends @Nullable Object> {
   // Returns the first non-null element, if such element exists.
   MyOptional<E> firstNonNull() { … } // problem here!
 }

 MyList<@Nullable String> maybeNulls = …
 MyList<String> nonNulls = …
 

Because MyOptional accepts only non-null type arguments, we need both maybeNulls.firstNonNull() and nonNulls.firstNonNull() to produce the same return type: MyOptional!<String!> (see notation). However, as specified above, they won't do that. In fact, there is a problem with the firstNonNull signature, since the type argument String? would not meet the requirements of MyOptional's type parameter.

The solution is to project the type argument to its non-null counterpart:


 // Returns the first non-null element, if such element exists.
 MyOptional<@NonNull E> firstNonNull() { … } // problem fixed!
 

Here, @NonNull E selects the non-null form of the type argument, whether it was already non-null or not, which is just what we need in this scenario.

If E has a non-null upper bound, then the apparent projection @NonNull E is redundant but harmless.

Nullable projection serves the equivalent purpose in the opposite direction, and is far more commonly useful.

If a type variable has all its usages being projected in one direction or the other, it should be given a non-null upper bound, and any non-null projections can then be removed.

Where it is not applicable

@NonNull is inapplicable in all the same locations as Nullable.