Annotation Interface NullMarked
@Documented
@Target({MODULE,PACKAGE,TYPE,METHOD,CONSTRUCTOR})
@Retention(RUNTIME)
public @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
Objectis filled in by the compiler. This means the exampleclass MyList<E>is interpreted identically toclass MyList<E extends Object>, making the upper bound non-nullObject. (Why?) - When a type parameter has a nullable upper bound, such as the
Einclass 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 havenullassigned to it. - Any type usage where
@Nullableand@NonNullare 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.javafile 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
modulekeyword). 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
@NullMarkedand@NullUnmarkedappear together on the same element, neither one is recognized.