JSpecify Nullness (Java)
Quick start
- Use
@NullMarkedto make unannotated types non-null by default. - Add
@Nullableonly where null is allowed; use@NonNullsparingly when you must override a nullable type variable use. - Decide type parameter bounds up front:
<T extends @Nullable Object>allows nullable type arguments,<T>does not. - Use
@NullUnmarkedto opt out of@NullMarkedin legacy or incremental areas. - Keep annotations in recognized type-use positions (arrays, nested types, type arguments).
- Read
references/jspecify-nullness.mdfor migration steps, syntax pitfalls, and tooling details.
Workflow
- Confirm tool support and constraints (nullness checker, Kotlin version, annotation processors).
- Add the
org.jspecify:jspecifydependency and expose it to consumers. - Annotate nullable types first, then add
@NullMarkedat class or package scope. - Fix generics: set bounds for type parameters and annotate type-variable uses as needed.
- Run nullness analysis, resolve findings, and repeat for adjacent code.
Rules of thumb
- Treat unannotated types outside
@NullMarkedas unspecified nullness, not non-null. - Do not annotate local-variable root types; annotate only type arguments or array components there.
- For arrays,
@Nullable String[]means nullable elements, whileString @Nullable []means a nullable array. - For nested types, use
Map.@Nullable Entryto mark the nested type, not the outer type. - Use
@Nullableon a type variable usage only when null is allowed even if the type argument is non-null.
Output expectations
- Provide annotated signatures and call-site implications.
- Call out tool-conformance limits rather than promising specific diagnostics.
References
- Load
references/jspecify-nullness.mdfor full guidance and examples.