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
Check Null
- Check Method Arguments for null early and throw exception (IllegalArgumentException) with meaningful error message
Objects.requireNonNull(arg, "arg must not be null");
- Lombok @NonNull
- Read the document or source code and find out whether the method may return null.
- For example
file.listFiles()
can return null if it’s not a folder or doesn’t exist
- For example
- If not sure whether the method may return null or nor, be defensive: check null.
Detect NPE and other bugs in IDE or Maven/Gradle
- @NonNull and @Nullable with Checker Framework
- Don’t use @Nonnull; non-nullability is implied.
- Use AbstractPackageSanityTests, ClassSanityTester or NullPointerTester to validate these annotations.
Use null safe methods and libraries
- Call methods on known literal rather unknown object
"constant".equals(object);
instead ofobject.equals("constant");
- Use
java.util.Objects#equals
- Use
String.valueOf(object)
overobject.toString()
- instanceof is null-safe: no need to check null
// StringUtils from apache commons-lang
IsEmpty/IsBlank()
StringUtils.// from commons-collections4
is(Not)Empty(col); CollectionUtils.
Return empty collection/array, instead returning null
- Effective Java Item 54: Return empty collections or arrays, not nulls
- As client would usually forget the null check.
return Collections.EMPTY_LIST
Throw exceptions instead return a null or an empty string
Unboxing and NullPointerException
When mix wrapper class and primitive type, Java will auto unbox the wrapper class to primitive type(boolean, int, long, etc), if the wrapper class is Null, then it would throw NullPointerException.
Map<String, Boolean> map = new HashMap<>();
if (map.get(key)) {}
In the above code, when map doesn’t contain the key, or its value is null, it would throw NullPointerException. One fix is to use Objects.equals
NullPointerException related with Collection
Check whether collection is Null before loop
for(variable: collection)
will throw NullPointerException if the collection is null.
Copying between different collection may throw NullPointerException
Copy between different collections may throw NullPointerException when the destination collection deosn’t allow null key or null value and the source collection contain null key or values.
For example ImmutableMap.copyOf(another_map)
may throw NullPointerException when the other map contains null key or null value.
com.google.common.collect.CollectPreconditions.checkEntryNotNull(CollectPreconditions.java:32)
at com.google.common.collect.RegularImmutableMap.fromEntryArray(RegularImmutableMap.java:99)
at com.google.common.collect.RegularImmutableMap.fromEntries(RegularImmutableMap.java:73)
at com.google.common.collect.ImmutableMap.copyOf(ImmutableMap.java:469)
at com.google.common.collect.ImmutableMap.copyOf(ImmutableMap.java:442)
Use Advanced Data Structure: Multimap, HashBasedTable
- Use Multimap instead of
Map<T1, List<T2>>
- Use
HashBasedTable, TreeBasedTable
instead ofHashMap<R, HashMap<C, V>>, TreeMap<R, TreeMap<C, V>>
- Multimap.get(key) return an empty collection when it doesn’t contain the key
- Same for Table: HashBasedTable, TreeBasedTable
- Bad smell: check a collection is empty or null
if(map.contains(key) && !map.get(key).isEmpty) {}
Avoid null key or null value in the collection
- New collection in Java, Collection in Guava doesn’t allow null key and null values
- handle them separately
Carefully check whether a k/v collection can store null value, refer to the table below:
Collection | Key | Value | Note |
---|---|---|---|
Hashtable | Null is not allowed | Null is not allowed | Thread-safe |
ConcurrentHashMap | Null is not allowed | Null is not allowed | Segment lock |
TreeMap | Null is not allowed | Null is allowed | Thread-unsafe |
HashMap | Null is allowed | Null is allowed | Thread-unsafe |
Rules for using primitive data types and wrapper classes
- Members of a POJO class must be wrapper classes.
The return value and arguments of a RPC method must be wrapper classes.
[Recommended] Local variables should be primitive data types.
Note: In order to remind the consumer of explicit assignments, there are no initial values for members in a POJO class. As a consumer, you should check problems such as NullPointerException and warehouse entries for yourself.
Positive example: As the result of a database query may be null, assigning it to a primitive date type will cause a risk of NullPointerException because of autoboxing.
Counter example: Consider the output of a transaction volume’s amplitude, like ±x%. As a primitive data, when it comes to a failure of calling a RPC service, the default return value: 0% will be assigned, which is not correct. A hyphen like - should be assigned instead. Therefore, the null value of a wrapper class can represent additional information, such as a failure of calling a RPC service, an abnormal exit, etc.
Use Optional Class
- Return Optional
instead of a nullable Bar - We can still use nullable references for instance variables or parameters of function.
Check null for a chain of method calls
- Use Optional
of(new Outer())
Optional.map(Outer::getNested)
.map(Nested::getInner)
.map(Inner::getFoo); .
- Use a supplier function
public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
get();
T result = resolver.return Optional.ofNullable(result);
}catch (NullPointerException e) {
return Optional.empty();
} }
Check Null explicitly, don’t catch NullPointerException
Do not catch Runtime exceptions defined in JDK, such as NullPointerException and IndexOutOfBoundsException. Instead, pre-check is recommended whenever possible.
Convenience methods to work with Null
com.google.common.base.Strings.isNullOrEmpty(String)
isNullOrEmpty for collections
- CollectionUtils.isEmpty() in commons-collections.
Other NullPointerException Cases
- Database query may return null.
- Data stored in session may be null.
- Collection.get may return null,
for(XType data: collection)
may throw NPE. - Rpc may return null.
- objectA.getB().getC().getD() may throw NPE.
- switch(enumValue) may throw NPE when its null.
- Using synchronized on a null object
- Throwing an exception which is null
// Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs
listFiles();
AbstractFile[]
getMessage() may be null. throwable.
Check Whether nullable
Method m = c.getDeclaredMethod("parsResponse", Response.class);
m.invoke(request, response);
- Check javadoc of
Request.parsResponse
to check whether it’s nullable.
NullPointer Bugs
Map<Boolean, List<String>> map = collect(Collectors.partitioningBy(TableSyncResult::syncSucceeded));
map.contains(false), map.contains(true) always returns true. We should use !map.get(false).isEmpty()
Resources
- UsingAndAvoidingNullExplained
- https://github.com/alibaba/p3c