10 Tips To Handle Null Effectively

When I started programming in Java, I considered the null value my enemy and I dreaded NullPointerExceptions that happened fairly often to me. Over time I learned working with it and nowadays I can consider my personal battle with nulls a victory. Most NPEs that I see nowadays are caused by incorrectly set up mocks during development. I can’t even remember the last time I caused an NPE in production environment. Enough bragging, here’s my list of practices when dealing with null values.

1. Don’t overcomplicate things

Handling nulls can be a complicated problem on its own and therefore we should make it as clean and as obvious as possible. One very bad practice that I’ve seen in some codebases is using Objects methods, Optional class or even a separate method using Optional in places where a simple null check would be enough. This caused me to check where the method comes from, what does it contain and wonder what’s the difference between this and direct comparison. Of course, our mileage may vary, but for me this is significant overhead that we should avoid.

2. Use Objects methods as Stream predicates

Although Objects.isNull and Objects.nonNull are not the best fit for typical null checks, they are a perfect fit to use with streams. The filtering or matching lines with them read (arguably) much better than those with operators. In fact, this is the reason why they were introduced in the JDK.

3. Never pass null as an argument

This is one of the most important principles of good coding, but if you don’t know it already, you deserve some explanation. Passing null to indicate that there’s no value for a given argument might seem like a viable option. But it has 2 big disadvantages:

  1. You need to read the function’s implementation and figure out if it and every potentially affected function down the way can handle null value correctly.
  2. You have to always be careful when changing function’s implementation, not to throw away something that might handle nulls for it’s users. Otherwise, you have to search through the whole source code to check if null is being passed anywhere.

By accepting the principle of never passing null, both of these problems are gone forever. And what about a function with optional parameters? It’s simple, just overload the function with different sets of parameters:

By the way, since the two disadvantages are not that visible in scope of a single class, you can give up on the rule when dealing with private methods. Just make sure things are safe from the outside.

4. Validate public API arguments

You and your team might use the principle of not passing nulls with great success, but when you’re exposing a public API, you have no control over it’s users and what they pass to your functions. For this reason, always check the arguments being passed to your public APIs for correctness. If your only concern is the nullity of the argument, consider using the requireNonNull function from the Objects class:

5. Leverage Optional

Before Java 8 it was common that a method would return null in case of a missing value. This was inherently error prone as the developer had to always check the documentation or, if the documentation was missing, the underlying source code for the possiblity of null being returned. Since JDK 8 we have the Optional class available, designed specifically to indicate that a return value might be missing. A developer calling a method with Optional as the return value has to explicitly handle the case when the value is not present. Therefore, wrap your return types with Optional when applicable.

6. Return empty collections instead of null

We already know that null is not the best return value for a method and that we can make use of  Optional class to indicate that the value might be missing. But things are a bit different when we’re talking about collections. Since a collection can contain any amount of elements, it can also contain… 0 elements! There are even special emptyXxx methods in the Collections class that return such collections. Therefore, we should avoid returning null or complicating things with Optional and return an empty collection when there are no values to fill it with.

7. Optional ain’t for fields

As I already said, Optional was designed to indicate missing return values. One tempting case that it was not designed for and surely is not necessary is class’ fields. By the means of encapsulation, you should have full control over the fields value including null. On the other hand, making fields optional explicitly might bring you weird problems like:

  • How should you write a constructor or setter for such a field?
  • You have to deal with the Optional even in cases when you’re sure that the value is there.
  • How should automappers handle those fields?

Therefore, use direct references for fields and carefully analyze whether a field can be null or not at any given point. If your class is well encapsulated, this should be fairly easy.

8. Use exceptions over nulls

One strange case when you might see people using null is exceptional situations. This is an inherently error prone practice as critical errors can be omitted or resurface in different places of the system, causing debugging a pain. Therefore, always throw an exception instead of returning null if something went wrong.

9. Test your code

Well, this advice is related to all kinds of bugs, not just unexpected nulls, but it’s so important that I felt it should make it to the list. Testing your code thoroughly using environment similar to production is a great way to prevent NPEs. Never release a piece of code without making sure it works. There’s nothing like “quick simple fix that doesn’t require testing”.

10. Double check

Every time you assume that some reference cannot be null, double check that you’re right. This is especially important when dealing with huge legacy databases or external providers. With the former, take the time to check if the columns you’re meaning to use do not contain any null values and if they do, check if those rows can make it into your system. In case of external providers, rely on contracts, documentation and if you’re not sure, send an email or call someone to make sure your assumptions are right. This might be annoying, especially when working with a poorly documented API, but when it comes to nulls: better safe than sorry!

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on:
  • Or… just use Kotlin! 🙂

    • Well. Since I’m used to Java verbosity and I learned working with it’s issues (like the null handling), I don’t see Kotlin as a game changer. At the same time, I can imagine that a lot of new or less enduring developers can see it as a great replacement for Java.

      • Even with all your great advices, Kotlin handle nulls better. Let me show you 🙂

        First and most valuable – type system! Kotlin force you check for null, where null possible, doesn’t allow pass null in place what is expecting non null etc.

        But how Kotlin can help in your cases:

        2. Use Objects methods as Stream predicates

        In Kotlin we have built in method like: filterNotNull, mapNotNull, etc

        4. Validate public API arguments

        Kotlin do it for you!

        Just define argument as non nullable and Kotlin will generate checks for you!

        6-10. As I say in Kotlin null is special type in type system, example:

        String – this type represent only string, Kotlin compiler will not allow to assign null to such variable.
        String? – this type represent String or null, so you can assign null, but when you tried to use this variable, compiler will disallow using without proper checking.

        So in Kotlin you shouldn’t think about 6-10 🙂 Compiler will think for you!

        Also i should mention operators for working with null, so i just leave link to documentation here http://kotlinlang.org/docs/reference/null-safety.html#safe-calls

  • Kristjan Cocev

    this.bar = Objects.requireNonNull(bar, “bar must not be null”);

    I don’t agree, because this throws a NullPointerException when instead it should be an IllegalArgumentException…

    • Steffen

      Don’t agree either 🙂

      Since there is a never ending war going on between IAE or NPE in parameter-checking situations, imho it’s perfectly fine to throw an NPE in this case.
      One can easily argue that the IAE should be thrown, where some kind of range checking is required (or similar situations).
      So if in this case a non-null-reference is required, why not tell the client right on spot, what he did wrong?!

      Also, it is recommended to use this newly added method on the Objects class, as it is going to be used by the SDK itself and may evolve in future versions. Use the additional message to name the required argument and that’s it.

      OR throw and IAE as you suggested, because neither IAE nor NPE will ever be announced winner in this battle. 😛