Optionals : are bad practices still bad practices if everyone practices them ?

Yassin Hajaj
Jul 8 · 10 min read
Java architect explaining optionals

Introduction

Optional s have been introduced with Java 8 released in 2014. These objects are wrappers for other objects or primitives to express the fact that a value can be either present or absent.

This class has been presented along with some best and bad practices.

In this article, I’ll go through some of those and analyze whether these are relevant.

Optional : What is it ?

According to the Javadoc

The hugest feature you’ve ever witnessed, ever !

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors. A variable whose type is Optional should never itself be null; it should always point to an Optional instance.

We have a little more explanation from Brian Goetz himself on StackOverflow

[…] But we did have a clear intention when adding this feature, and it was not to be a general purpose Maybe type, as much as many people would have liked us to do so. Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”, and using null for such was overwhelmingly likely to cause errors.

For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list. You should almost never use it as a field of something or a method parameter.

I think routinely using it as a return value for getters would definitely be over-use.

There’s nothing wrong with Optional that it should be avoided, it’s just not what many people wish it were, and accordingly we were fairly concerned about the risk of zealous over-use. […]

Now that we have a clear understanding of the intentions of the Java architects on what the purpose of Optional should be in their eyes, let’s investigate what this feature looks like in other languages such as Kotlin & C#.

Optional : In C# & Kotlin?

First of all, in C# & Kotlin, optional or “maybe” references are natively part of the language. They are also, as we can imagine, compile-time features and provide quick feedback to developers.

In C# int? nullableInt = null;

In Kotlin var nullableString: String? = null;

But still, it provides the same kind of flexibility to the developers as Optional brings : a way for developers to express a “maybe” reference.

So why can’t we use Optional to provide us with a similar comfort in Java?

Actually, we could, but…

Thanks Donald

It was not intended to be like that, the Java architects haven’t created the class for this purpose and thus leaving developers in a doubt about WHICH best practices to use.

I think routinely using it as a return value for getters would definitely be over-use.

This sentence represents a piece of explanation on why the confusion persists : what is routinely? Why can’t we let developers decide whether they want to use Optional getters (as it makes the most sense in some cases).

Though we can also see that in this article posted on the Oracle’s blog that not only getters but even FIELDS are used as Optionals in an example of how to use Optionals

public class Computer {
private Optional<Soundcard> soundcard;
public Optional<Soundcard> getSoundcard() { ... }
...
}

public class Soundcard {
private Optional<USB> usb;
public Optional<USB> getUSB() { ... }
}

This generates a warning in IntelliJ as you could imagine, and for good reasons

IntelliJ’s “Optional as field or parameter” inspection message

So what to believe ?

I would say to go with what matters the most : writing readable, maintainable & testable code as usual with a little extra called team agreement to make sure everyone working in the code is on the same page.

The example coming from the example above could be refactored as such, avoiding inspection of IntelliJ and easing development still. We just needs to make sure that the getters for which we’ll be returning an Optional can effectively be null and is not a result of the NullPointerException paranoia.

public class Computer {
private Soundcard soundcard;
public Optional<Soundcard> getSoundcard() {
return Optional.ofNullable(soundcard);
}
...
}

public class Soundcard {
private USB usb;
public Optional<USB> getUSB() {
return Optional.ofNullable(usb);
}
}

This example brings us to a discussion regarding the @Getter feature of lombok and whether it should or not include the possibility to have Optional getters

Lombok : At the service of developers ?

Java champion pointing finger at a developer that is obviously doing it wrong (duh)

As shown earlier, the use of Optional getters could be considered a good use of optionals while at the same time being discouraged by a number of Java champions and Java architects.

But why?

Let’s begin with the following issue raised on lombok’s GitHub repository :

Any reason why we can’t have an OptionalGetter annotation?
[…]
I’ve read the responses to Optional around here and how the authors seem to generally hate it, and I agree that it pretty much never makes any sense to have an API take in some type Optional<T> parameter.
However, are there any arguments against having something like @OptionalGetter?
[…]
There are a lot of instances where I’d like to more clearly indicate “no value set yet” rather than just returning null to the caller.

To which the cofounder of Lombok himself responded in the following way

[…] Sorry to disappoint you all: We’re not adding this. PRs with this feature will not be accepted. Discussing the merits and downsides of optional would probably take more time and words than working out how to achieve world peace, so, please don’t try to extol optional’s virtues here.

Which brings us to the conclusion that the Projectlombok is not totally at the service of its users. It would be great if these changes were at least possible to discuss. I think lombok would totally win a lot by allowing this feature to be implemented.

This is also clearly expressed by jroper in the last intervention of the issue

I don’t think it makes sense to argue here about how someone should use Optional. The fact is, there are multiple different opinions, with large groups behind each. For example, talk to anyone with a Scala background that is doing Java, and they will tell you that Optional should be used as much as possible in place of nulls everywhere, because that’s exactly how Scala uses it with its equivalent Option type. Now whether they are right or wrong is beside the point, people with this opinion exist, and they form a significantly sized portion of the lombok user community, and would benefit from better support for Optional in lombok. As an example of such a community, the Java APIs for Play Framework, Lagom and Akka all make strong use of Optional in fields and as method parameters, and all three of those frameworks recommend using lombok for immutable Java classes. These are large communities that have this opinion, it’s not a fringe view.

So the question is, is the use of Optional something that lombok itself should have an opinion on? I don’t see why it should. Providing better support for Optional fields won’t have any negative impacts on people whose opinion it is that you shouldn’t use Optional fields, because they’re not going to use Optionalfields and so they’ll never see that support. But it will certainly help those whose opinion it is that you can/should. And it doesn’t seem to be a feature that would have a very high cost to implement or require significant refactoring in lombok. So why hold out on this portion of your users?

Bad practices : religion or pragmatism?

In this discussion, it seems obvious that blindly following principles as if they were the one and only truth is not always the best mindset regarding different kinds of situations.

In this part, we’ll checkout some bad practices and analyze whether they really are bad practices or if pragmatism can justify to use them

Case 1 : Stream.ofNullable(...).orElse(...)

Bad : String value = Optional.ofNullable(someString).orElse("wasNull");

Good : String value = someString == null ? "wasNull" : someString;

The bad situation here is considered bad for the following reasons :

  • Object allocation (Optional instance) unnecessary
  • More difficult to read

The question now is : would you use the first solution in your code ?

Your answer probably is : it depends, and you’re right. And it should be the answer to a lot of questions related to programming in general.

What does it depend of ? Well, if your team really finds it difficult to read, then just stick to the traditional null check. Otherwise, let’s speak about performance and unnecessary object allocation.

If your decision is to use this kind of code in an area of your code experiencing a lot of trafic, a lot of object allocation, think about it twice.

But what if your application doesn’t have these kind of problems, or what if you’re using this in an area of your app not really impacted by performance issues. Well, then go for it, it’s that easy.

“Can we use it in our code Java Ninja ?”

Case 2 : Optional as parameter or field

We saw it earlier, using an Optional as a parameter or a field is not really advised. But, is it a subjective rule or does it make sense in general?

Let’s take a look at what it could look like, let’s write a bean with one field and a setter, this will cover our use case.

public class Person {
private Optional<String> name;
public void setName(Optional<String> name) {
this.name = name;
}
}

Mmh, we can already see some problems here. Are we really wanting the invoker the wrap the name value inside of an Optional . Plus, if he wants to do that, then it means that the value is probably always present (unless he has the bad idea of setting the name to null ).

Let’s correct our example to get rid of the optional-as-a-parameter

public class Person {
private Optional<String> name;
public void setName(String name) {
this.name = Optional.of(name);
}
}

Still, this doesn’t feel really natural, does it? We have another problem here, remember the Javadoc? No worries, I got you

A variable whose type is Optional should never itself be null; it should always point to an Optional instance.

Not really the case here mh? Ok let’s correct it again

public class Person {
private Optional<String> name = Optional.empty();
public void setName(String name) {
this.name = Optional.of(name);
}
}

Feels better now? NO. Still something fishy.

What if we want to serialize our object, knowing that Optional fields are not serializable? Well, we’re facing an issue again.

I think we’ve put enough energy in proving this is really not an ideal pattern. We could still use Optional Getters if really needed and if semantically makes sense, but let’s forget about Optional fields and parameters.

NO.

Case 3 : Functional style programming

Using Optional’s functional construct is discouraged by Stuart Marks himself during the following talk (at 30:00)

Stuart Marks — Optional — The Mother of All Bikesheds (@ Devoxx Belgium)

Bad

Optional<BigDecimal> first = ...
Optional<BigDecimal> second = ...
Optional<BigDecimal> result = Stream.of(first, second)
.filter(Optional::isPresent)
.map(Optional::get)
.reduce(BigDecimal::add);

Good

Optional<BigDecimal> first = ...
Optional<BigDecimal> second = ...
Optional<BigDecimal> result;
if (!first.isPresent() && !second.isPresent()) {
result = Optional.empty();
} else {
result = Optional.of(first.orElse(ZERO).add(second.orElse(ZERO)));

I’ll let you judge by yourself, it probably is better to use the second kind of implementation if the team you’re working in is not still mature enough to read and understand directly what happens looking at functional implementations.

If it’s the case tho, you should probably use the first approach considered bad instead. It is more compact, clear, scalable to more bigdecimals, etc.

What do we say to functional programming Donald?

Delightful !

Case 4 : Collection of Optionals

This case is very clear : why have a collection of Optional objects where you can have a collection of those unwrapped objects with only those who fulfil to Optional.isPresent() == true .

This is a very clear example of how not to use optionals. When building your collection, just ommit those who shouldn’t be present there in the first place and you’re good to go.

So Donald?

Absolute no ! Quack !

Conclusion

There are certainly more matters to discuss regarding optionals and their multiple use cases, the goal here was to highlight the fact that there was not one unique opinion to be followed regarding the optionals.

Even if the rules have been presented by the creators themselves, those rules can be discussed and put in perspective.

Projectlombok should in my honest opinion implement the @OptionalGetter feature a way or the other as a lot of its users use them already.

If you encounter an article about how to use or not to use optionals or any other language feature in the future, ask yourself whether those arguments apply to your programming environment too.

Bye Bye !
Yassin Hajaj

Written by

I’m a developer who has a thing for artificial intelligence !

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade