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 null-marked
code: 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.
For a comprehensive introduction to JSpecify, please see jspecify.org.
Effects of being null-marked
Within null-marked code, as a general rule, a type usage is considered non-null (to
exclude null as a value) unless explicitly annotated as Nullable. However, there
are several special cases to address.
Special cases
Within null-marked code:
- We might expect the type represented by a wildcard (like the
?inList<?>) to be non-null, but it isn't necessarily. It's non-null only if itextendsa non-null type (like inList<? extends String>), or if the class in use accepts only non-null type arguments (such as ifListwere declared asclass List<E extends String>). But ifListdoes accept nullable type arguments, then the wildcards seen inList<?>andList<? super String>must includenull, because they have no "upper bound". (Why?)- Conversely, a type parameter is always considered to have an upper bound; when
none is given explicitly,
Objectis filled in by the compiler. The exampleclass MyList<E>is interpreted identically toclass MyList<E extends Object>: in both cases the type argument inMyList<@Nullable Foo>is out-of-bounds, so the list elements are always non-null. (Why?)
- Conversely, a type parameter is always considered to have an upper bound; when
none is given explicitly,
- Otherwise, being null-marked has no consequence for any type usage where
@Nullableand@NonNullare not applicable, such as the root type of a local variable declaration. - When a type variable has a nullable upper bound, such as the
Einclass Foo<E extends @Nullable Bar>), an unannotated usage of this type variable is not considered nullable, non-null, or even of "unspecified" nullness. Rather it has parametric nullness. In order to support both nullable and non-null type arguments safely, theEtype itself must be handled strictly: as if nullable when "read from", but as if non-null when "written to". (Contrast withclass Foo<E extends Bar>, where usages ofEare simply non-null, just like usages ofStringare.) - By using
NullUnmarked, an element within null-marked code can be excluded and made null-unmarked, exactly as if there were no enclosing@NullMarkedelement at all.
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. Special considerations:
- To apply this annotation to an entire (single) package, create a
package-info.javafile there. This is recommended so that newly-created classes will be null-marked by default. 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. For example, a package-info file from atestsource path might hide the corresponding one from themainsource path, or generated code might be compiled without seeing a package-info file at all. - Although Java permits it to be applied to a record component declaration (as in
record Foo(@NullMarked String bar) {...}), this annotation has no meaning when used in that way. - Applying this annotation to an instance method of a generic class is acceptable, but is not recommended because it can lead to some confusing situations.
- An advantage of Java modules is that you can make a lot of code null-marked with
just a single annotation (before the
modulekeyword).NullUnmarkedis not supported on modules, since it's already the default. - If both
@NullMarkedand@NullUnmarkedappear together on the same element, neither one is recognized.