Annotation Interface NullMarked


Indicates that the annotated element and the code transitively enclosed within it are in null-marked context: there, type usages are generally considered to exclude null as a value unless specified otherwise. Using this annotation avoids the need to write @NonNull many times throughout your code.

Conversely, NullUnmarked puts its enclosed code in null-unmarked context, the same as unannotated code. These annotations work as an inclusion-exclusion pair: of the annotations of either type on all enclosing elements (methods, classes, etc.), only the nearest (most narrowly enclosing) one is in effect.

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

Effects of being null-marked

In null-marked context, a type usage is generally considered to be non-null unless explicitly annotated with @Nullable. However, there are a few special cases to address.

Special cases

Within null-marked context:

  • A wildcard (as seen in List<?>) generally represents a nullable type, unless either it or its corresponding type parameter has a non-null upper bound. (Why?)
  • A type parameter itself is a different case. It is never really "unbounded"; if no upper bound is given explicitly, then Object is filled in by the compiler. This means the example class MyList<E> is interpreted identically to class MyList<E extends Object>, making the upper bound non-null Object. (Why?)
  • When a type parameter has a nullable upper bound, such as the E in class Foo<E extends @Nullable Bar>, an unannotated usage of the associated type variable (within that class) must be handled conservatively: it is nullable when read, yet cannot have null assigned to it.
  • Any type usage where @Nullable and @NonNull are not applicable, such as the root type in a local variable declaration, is unaffected by being in null-marked context.

Where it can be used

@NullMarked and @NullUnmarked can be used on any package, class, method, or constructor declaration; @NullMarked can be used on a module declaration as well. (@NullUnmarked is not supported on modules, since it's already the default.) Special considerations:
  • To apply these annotations to an entire (single) package, create a package-info.java file and annotate the package declaration there. This annotation has no effect on "subpackages". Warning: if the package does not belong to a module, be very careful: it can easily happen that different versions of the package-info file are seen and used in different circumstances, causing the same classes to be interpreted inconsistently.
  • An advantage of Java modules is that you can put a lot of code in null-marked context with just a single annotation (before the module keyword). Warning: Even if you annotate the module for a library as @NullMarked, this has no effect for users who place the library on the class path; it affects only those who place the library on the module path, which is less commonly used.
  • Applying this annotation to an annotation interface does not express that annotations of that type are synonymous with @NullMarked. It has the same meaning as it does anywhere else.
  • If both @NullMarked and @NullUnmarked appear together on the same element, neither one is recognized.