Consistent Null Values Handling in Java
Learn more about consistent null values handling in Java.
Join the DZone community and get the full member experience.Join For Free
The handling of
null values are often considered a weak spot in Java, and there are several reasons for it.
The most frequently mentioned issue is the famous
NullPointerException, although there is no clear justification as to why this is an issue. After all, this is just a sign of the problem, but not the problem itself.
The actual problem is deeper. Those who have experience writing code with C or C++ know this issue well. While coding in C/C++, engineers should always keep in mind countless nuances related to access safety, undefined behaviors, memory allocation, object copying/moving, and so forth. All these numerous details create constant "pressure," consume precious engineer brain resources, and result in slower development speed. Even hardcore C/C++ proponents can't deny this fact.
A similar problem exists with
null values in Java.
You may also like: 10 Tips to Handle Null Effectively
Java is often considered a verbose language. That's true. This is the backside of its explicitness. Almost every intent in Java can be (and usually is) explicitly expressed in code. By adding some extra text, we, in turn, get immediately accessible context, which doesn't need to be carried in the head while reading Java code. The
null values break this rule. They don't manifest themselves in the code.
null values may appear for various reasons. It can be default initialization, the value returned from some method, or even explicitly assigned
null value. Keeping in mind that sometimes
null's may appear, checking method documentation or code for the possibility to return such value — all these creates "pressure" very similar to described above for C/C++.
What can be done to solve this issue? How can we remove the constant "pressure" that affects our productivity?
Of course, there is more than one way to solve it.
@NotNull(or alike) annotations. Does, basically nothing, except adding some (false) feeling that
nullvalues are somehow handled.
- Establish strict rules and check every value which potentially be
null. It's a working solution, but at the expense of polluting code with countless
nullchecks. And, well, nobody is perfect; we can make mistakes and the compiler will not help us.
- Invent own language. Authors of Kotlin have done just that. Again, this is a working solution, but it's overkill for me. Nevertheless, it has one important thing: nullable and non-nullable types are distinct and clearly expressed in the code.
- Use functional programming approaches —
Maybemonad in some form.
The last point is what I'm going to discuss in more detail.
Optional: The Good, The Bad, and The Ugly
Introduced in Java 8,
Optional class is targeted to handle missing values instead of
null. To some extent, it is a Java implementation of
Maybe monad (but not completely, see below).
While some can consider this as just a fancy way to work with
null values, it actually has a far more important benefit: explicit expression of intent. Once you wrap a field, parameter, or variable into
Optional, you immediately making your intent explicit and clear to the reader. In other words, you're adding that missing context. At the same time, the compiler starts seeing a difference, so you're not alone anymore.
So, by using
Optional, an engineer kills three birds with one stone:
- Makes potentially missing value explicit in code and removes "pressure" from the reader.
- Enables compiler to control access to the value.
- Makes handling of
Optional has its own issues.
As mentioned above,
Optional "to some extent" implementation of
Maybe monad. It makes reverences to imperative world and has externally accessible value. By calling the
get() method, you can try to retrieve it. But if you do, it may throw
NullPointerException, which defies the whole purpose of the
Optional — be safe container for potential
null (i.e. missing) values.
Perhaps this is why some smart heads suggest that "using
Optional for fields and parameters is bad practice" and static analysis tools show warnings for such usage of
The solution might be to write your own version of
Maybe and use it instead. There are several different implementations around. I'm using one from my Reactive Toolbox Core library.
Maybe enables Java engineers to use the following convention:
- Every variable/field/parameter with plain type is not null and never can be.
- Every variable/field/parameter whose type is wrapped into
Maybe— potentially can be empty.
- If some external library/call can return
nullvalue, the result should be immediately wrapped into
Without any additional efforts, strict following the convention above enables writing Java code which:
- Never throws
NullPointerExceptionand have all
nullvalues handled properly.
- Clearly and explicitly distinguishes nullable and non-nullable values in code and lets compiler enforce this distinction at compile time.
10 Tips to Handle Null Effectively
Java 8 Optionally: Handling Nulls Effectively
Published at DZone with permission of Sergiy Yevtushenko. See the original article here.
Opinions expressed by DZone contributors are their own.
Introduction to API Gateway in Microservices Architecture
5 Common Data Structures and Algorithms Used in Machine Learning
Decoding eBPF Observability: How eBPF Transforms Observability as We Know It