Related Posts
- How to Avoid NullPointerException in Java Part 1
- How to Avoid NullPointerException in Java Part 2
- Avoid Call Instance Method in Constructor to Prevent NullPointerException
Don’t be unnecessarily null tolerant
- Don’t use @Nonnull; non-nullability is implied
- Assume nonnull unless @Nullable explicitly
- Check Method Arguments for null early and throw exception (IllegalArgumentException) with meaningful error message
- Use
Preconditions.checkNotNull()
orVerify.verifyNotNull()
to convert a @Nullable value into a non-null.
Use Non-Null Default Value
- Use empty collections over null
- Use empty string over null
- Use Optional
instead of a Nullable Foo - Use empty array instead over null Good Example:
@Override
public byte[] NoOpDb.key() {
return new byte[0];
}
Bad Example:
@Override
public byte[] NoOpDb.key() {
return null;
}
@Nullable at Method Parameters
- Add @Nullable to method params help prevent bugs in future change.
// params is non-null, and the elements in params are also non-null.
public void method(String... params) {}
// params may be null, but the elements in params are non-null.
public void method(String @Nullable ... params) {}
// params is non-null, and the elements in params are nullable.
public void method(@Nullable String... params) {}
Use a local variable
If the map is mutable, the value maybe null when refer it later.
if (instanceMap.containsKey(key)) {
String value = instanceMap.get(key)
}
We can use lock to fix the issue, or in some cases, we can just save the value in a local varible.
String value = instanceMap.get(key);
if (value != null) {
}
@UnderInitialization
If a method has @UnderInitialization, it can be called only from constructor.
@RequiresNonNull("context") // This method requires context is non-null.
@EnsuresNonNull("resources") // resources will be non-null.
private void init(@UnderInitialization MyClass this) {
getResources();
resources = context.
}
private void init1(@UnderInitialization(ParentClass.class) MyClass this) {
// You can access to parent-class's fields here.
}
private void init2(@UnderInitialization(MyClass.class) MyClass this) {
// You can access to all fields here.
}
@UnknownInitialization
@UnknownInitialization will act like all fields in the class are @Nullable requiring null checks for even non-null fields.
Use @Nollable
- Use
org.checkerframework.checker.nullness.qual.Nullable
which is more powerful. Which can be used on types.
MonotonicNonNull
- Use @MonotonicNonNull if once the field becomes non-null, it never becomes null again/
UnderInitialization
When to use @Nullable
- Add @Nullable to method return value tells the caller the need to check the nullness.
- Add @Nullable to method params help prevent bugs in future change.
- method that never returns null should still be marked @Nullable if its subtypes may return null.
Array
arrays can both be null, and contain null objects:
Object[] array
is same as@NonNull Object @NonNull [] array
: Non-null array of non-null elements.- @Nullable Object[] is a non-null array of nullable objects, and Object @Nullable [] is a nullable array of non-null objects.
import org.checkerframework.checker.nullness.compatqual.NullableType;
String @Nullable [] array = null; // Nullable array of non-null elements
new String[] {null}; // ERROR!
array =
@Nullable String[] array = new String[] {null}; // Non-null array of nullable elements.
null; // ERROR!
array =
@Nullable String @Nullable [] array = new String[] {null}; // Nullable array of nullable elements.
null; // OK.
array =
Array<@NullableType String> array; // Non-null array with nullable elements.
String @NullableType[] array // Nullable array of non-null objects.
toArray()
- Use
list.toArray(new TheType[list.size()])
instead oflist.toArray(new TheType[list.size()])
, as nullness checker can’t infer that the size of the array you created is the same size as the collection passed in.
Generics
@Nullable ListUseful Checker Annotations for Nullness Analysis
EnsuresNonNullIf
: ensures that some fields/methods will be/return non-null if the return value satisfy a condition.@EnsuresNonNullIf(expression = "list", result = true)
public boolean hasNext() {
return list != null && index < list.length;
}@EnsuresNonNullIf(expression="#1", result=true)
@SuppressWarnings
@SuppressWarnings("nullness:argument.type.incompatible")
instead of the broad scope @SuppressWarnings("nullness")