How to Avoid NullPointerException in Java Part 1


Check Null

  • Check Method Arguments for null early and throw exception (IllegalArgumentException) with meaningful error message
  • 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
  • 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 of object.equals("constant");
  • Use java.util.Objects#equals
  • Use String.valueOf(object) over object.toString()
  • instanceof is null-safe: no need to check null
// StringUtils from apache commons-lang
StringUtils.IsEmpty/IsBlank()
// from commons-collections4
CollectionUtils.is(Not)Empty(col);

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

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

if(map.contains(key) && !map.get(key).isEmpty) {}

Avoid null key or null value in the collection

Carefully check whether a k/v collection can store null value, refer to the table below:
CollectionKeyValueNote
HashtableNull is not allowedNull is not allowedThread-safe
ConcurrentHashMapNull is not allowedNull is not allowedSegment lock
TreeMapNull is not allowedNull is allowedThread-unsafe
HashMapNull is allowedNull is allowedThread-unsafe

Rules for using primitive data types and wrapper classes

  1. Members of a POJO class must be wrapper classes.
  1. The return value and arguments of a RPC method must be wrapper classes.

  2. [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.

Alibaba Java Coding Guidelines

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
Optional.of(new Outer())
    .map(Outer::getNested)
    .map(Nested::getInner)
    .map(Inner::getFoo);
  • Use a supplier function
public static <T> Optional<T> resolve(Supplier<T> resolver) {
  try {
      T result = resolver.get();
      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.

Alibaba Java Coding Guidelines

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
AbstractFile[] listFiles();

throwable.getMessage() may be null.

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

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)