Annotation Interface Nullable


@Documented @Target(TYPE_USE) @Retention(RUNTIME) public @interface Nullable
Indicates that the annotated type usage (commonly a parameter type or return type) is considered to include null as a value.

Example usages:

@Nullable String field;

@Nullable String getField() { return field; }

void setField(@Nullable String value) { field = value; }

List<@Nullable String> getList() { … }

For important information common to all four nullness annotations, see org.jspecify.annotations. To learn more about JSpecify, see jspecify.dev.

Meaning for each kind of type usage

Despite the itemized list here, the essential meaning of this annotation is always the same in every case: the type it annotates is considered to include null as a value. A good way to read @Nullable String in any context is "string-or-null". That's usually all you need to think about, but this section offers some additional explanation for each kind of context.

  • On a parameter type: See the setField example above. It permissively accepts a "string-or-null", meaning that it is okay to pass an actual string, or to pass null. (This does not guarantee that passing null won't produce an exception at runtime. Why?) Lambda expression parameters work in the same way if their types are written explicitly.
  • On a method return type: See the getField example above. It returns a "string-or-null", so while the caller might get a real string back, it might get null as well, and should be prepared for that possibility.
  • On a field type: See the field example above. It has the type "string-or-null", so it might hold a string and it might hold null. (If you are confident the containing object can't be observed in its uninitialized state, the field need not be annotated solely because it is null during initialization.)
  • On a type argument: Within the compound type MyList<@Nullable String>, we can see a usage of the type "string-or-null". To understand what @Nullable means here, read the MyList<E> API; every appearance you see of the E type will be treated as nullable (unless it has its own nullness annotation, which takes precedence). For a typical container type like this example, this means it can contain null elements; if your list itself might be null as well, we can write @Nullable MyList<@Nullable String>: a nullable list of nullable strings.
  • On the upper bound of a type parameter: For example, consider interface List<E extends @Nullable String>. This means that type arguments in that position may be nullable (as in List<@Nullable String>). A non-null type argument, as in List<String>, is permitted either way.
  • On a usage of a type variable: A type parameter, like the T declared in class Optional<T>, introduces a type variable of the same name, usable only within the scope of the declaring API element. All the preceding examples using String are equally valid for a type variable like E. @Nullable continues to mean "or null" as always, regardless of whether the type argument "already" includes null. For example, suppose that class Foo<E extends @Nullable Object> has a method @Nullable E eOrNull(). Then, whether a variable foo is of type Foo<String> or Foo<@Nullable String>, the expression foo.eOrNull() is nullable either way. Using @Nullable E in this way is called nullable projection.
  • On an array type: The nullness of the array and of its components can each be indicated separately. For example, in null-marked context, @Nullable String[] is a non-null array of nullable strings, and String @Nullable [] is a nullable array of non-null strings.
  • On a varargs parameter: Use @Nullable String... to indicate that the individual strings may be null. To let null be passed as the entire array, use String @Nullable ....
  • On a nested type: In most examples above, in place of String we might use a nested type such as Map.Entry. The Java syntax for annotating such a type as nullable looks like Map.@Nullable Entry.
  • On a record component: Java propagates all type-use annotations (including @Nullable) from a record component type to the type of the generated field, accessor method, and/or constructor parameter. If the constructor parameter list or accessor method is provided explicitly, it must still be annotated explicitly.

Where it is not applicable

This annotation and NonNull are applicable to any type usage except the following cases, where they have no defined meaning and should not be used:

  • On any intrinsically non-null type usage: one that is incapable of including null by the rules of the Java language, like the type following throws. A nullness annotation in this location could only be either contradictory or redundant.
  • On a local variable declaration (root type only). While the cases listed above benefit from declarative nullness, the nullness of a local variable is more properly determined through flow analysis (Why?). This rule applies only to the root type of the variable; type components, such as type arguments, follow the usual rules.
  • In a cast expression (root type only). To inform an analyzer that an expression it sees as nullable is truly non-null, use an assertion or a method like Objects.requireNonNull(T). (Why?) Type components, such as type arguments, follow the usual rules.
  • On any part of the argument to instanceof. The root type is intrinsically non-null, as discussed above, and nothing else about nullness is checked at runtime.
  • On any part of a receiver parameter type (JLS 8.4).
  • If both @Nullable and @NonNull appear on the same type usage, neither one is recognized.
Whether the surrounding code is in null-marked context also has no consequence in the above locations.

Unannotated type usages

For a type usage where nullness annotations are applicable but not present, its nullness depends on whether it appears within null-marked context; see NullMarked for details. Note in particular that nullness information from a superclass is never automatically "inherited." (Why?)