DEV Community


Posted on


Use Optional / Nullable Reference Types Judiciously

Languages such as Swift, Kotlin has a distinction in the reference types — Optional and Non-Optional references or Nullable and Non-Null types — where only an Optional or Nullable type can hold a nil or null reference.

Java SE 8 also has support for Optional, but the difference is that in Swift and Kotlin a normal field cannot hold a null reference. It has to be declared an Optional type to hold a null. Java is not that strict that it allows null reference to normal fields also, but it is possible to write better APIs in Java also using Optional.

All these type systems try their best to avoid the null references — the billion dollar mistake as the inventor of null reference Tony Hoare called it.

If you are switching from a language that doesn’t have Optional — like Java 7 or Objective-C — to a language that supports Optional, chances are that you merely translate all your fields to Optional. But that’s not a very good practice.

It is very important to understand what problem this Optional type solves. The advantage compared to the normal null references is that the Optional types forces you — or the client of your API — to think about the case when the value is not present.

That’s it. By declaring a field as an Optional you declare that it is possible that the field can be empty and it makes the clients of the API handle the empty value case.

Let’s assume there is a class, Customer and it has two fields: customerId and customerName. And for any customer, these two fields cannot be empty, logically.

If you declare these two fields as Optional, you declare that these fields can be empty. And this creates a potential for having a customer object in an invalid state in the runtime — that is a customer object that has empty id or name but which cannot be empty based on your business logics.

Having an object in an invalid state is more dangerous than a Null Pointer Exception as the invalid object will not crash your app but make your app behave in a weird manner and it is very hard to debug the cause.

So think hard before declaring a field as an Optional whether that field can be empty logically. If some fields cannot be null based on your business logics, don’t declare it as an Optional. If you need to declare some field that cannot be null logically as an Optional for some special use-cases, you may first have to think of other possibilities or restructuring your code rather than using Optional as the first choice.

Having every field as Optional references and using safe calls or optional chaining ( bob?.department?.head?.name ) to access the values might avoid you Null Pointer Exceptions in the beginning. But it will bite you in the long run as you might get null values even for the fields that cannot have null value logically and leave the objects in invalid states and worse you have no easy way to figure that out.

Top comments (2)

preslavrachev profile image
Preslav Rachev

As soon as we started using Java 8 at work, I became one of the biggest proponents of using Optional where possible. Soon, though, we realized that optionals in Java suffer from the same problem that they were supposed to help fix. As any other type in Java, an Optional wrapping a value can be NULL as well, unless it has been set to an empty Optional at initialization. This has led to many NPEs, because developers implicitly assumed that if a value wrapped in an Optional is NULL-safe, the same applies to the wrapping Optional.

Long story short, we reduced our use of Optional even in cases where a value could potentially be NULL. Instead, we reverted to using the @Nullable and @NonNull annotations, which most Java IDEs and static code analyzers can use to hint the developers if a Nullity check is needed.

P.S. Nullable types in Kotlin really differ from Optionals in Java in that by default variables in Kotlin must always have a value.

bob profile image

Yes. Optional will not just magically eradicate all our NPEs. But it is possible to write better code using Optional. As I said in the above post itself,

"The advantage compared to the normal null references is that the Optional types forces you — or the client of your API — to think about the case when the value is not present."

So now the client of the APIs should check whether the Optional has value or not before using it. For a non-optional variable, they can assume it will never be null. For Kotlin the system itself won't allow null reference to a non-optional. But in Java, we have to ensure we don't mistakenly allow a null reference to a non-optional field.