Enterprise Integration Zone is brought to you in partnership with:

Senior Java developer, one of the top stackoverflow users, fluent with Java and Java technology stacks - Spring, JPA, JavaEE. Founder and creator of http://computoser.com and http://welshare.com . Worked on Ericsson projects, Bulgarian e-government projects and large scale recruitment platforms. Member of the jury of the International Olympiad in Linguistics and the Program committee of the North American Computational Linguistics Olympiad. Bozhidar is a DZone MVB and is not an employee of DZone and has posted 91 posts at DZone. You can read more from them at their website. View Full User Profile

The Optional Type API

  • submit to reddit

Java 8 introduces the Optional class. In a nutshell, instead of returning null, and then checking for null, you return an Optional instance, which can either have or not have a value set. That way you don’t fail with NullPointerException.

I won’t discuss whether the Optional type will eliminate NPEs (it won’t). Instead I’ll discuss things from a different perspective – API design. In addition to Java’s Optional, I’ll show guava’s Optional and scala’s Option, and compare them.

An API, as Joshua Bloch suggests, should be as small as possible, but no smaller. The conceptual weight of an API should be minimized, and if you wonder whether to include something in your API or not, then you should leave it out. An API should be easy to use, and hard to misuse, and ideally should have one (or two) main usage patterns. The Optional type is a good example of having to make all these choices.

What is the default usage of this? You get an optional type, and you want to execute some piece of code only if there is a value set. You could obviously do that by comparing to null, but you often tend to forget that and the optional types force you to realize that this value can actually be unset. The second important use-case is to be able to easily provide a default value, if none is set.

Let’s first start with the worst of the three (in my opinion) – scala’s Option. At first it seems that this class offers you a lot of functionality. But, as it is normal for scala, there are a lot of different ways to use a class and none of them is better than the rest. For me, the particularly bad decision in this case is making Option (implicitly) convertible to Iterable. For the non-scala developers, let’s assume it is an Iterable. But it can have only one or zero elements. So, in order to implement our default and most common use-case we have the following options:

  • Use imperative style if (option.nonEmpty) {option.get.doSomething()}
  • Use .foreach – option.foreach(v => v.doSomething)
  • Use a foreach loop (different from above): for (value <- option) {value.doSomething()}
  • Use a for comprehension (for...yield) (different from the two above)
  • Use pattern-matching - case Some and case None
  • Use map, fold, collect, etc - this takes the process one step further - not only you get the value, but apply some function to it

So, from the basic notion of an optional type, we have a class with dozens of methods. The conceptual weight of this API is huge. There is no obviously preferred way to handle the most common case, and in fact method preferred by many scala developers uses some form of foreach, which sounds a bit weird, when you know there is at most one value.

Now let's proceed with my 2nd place candidate - Java 8 Optional. You have only two ways to use it - the imperative check with an if-clause, and the ifPresent(function) method, where you supply a function that handles the code when there is a value. You also have a couple of overloaded methods to provide a default value (the 2nd use-case). What I don't like is the mapflatMap and filter methods there. They are useful, as the scala ones above, but they could be left out (and their usage handled separately, with almost no added verbosity), or they could be reduced to simply one function - map. It has a subtle difference with flatMap, and filtering a single element isn't the most useful thing out there, besides, you could do that with a map function.

I know that by now you are probably ready to ask (angrily) how you are going to write very concise code without the ability to fold, collect, flatMap, filter. Returning another optional type after performing an operation with the given optional type is a 3rd use-case, which is important for long methods. It is less common than the other two, so less attention should be paid to it. Ideally, one method is enough - all other sub-usacases can be handled in the map function itself.

So we get to the winner - guava Optional. It has only the imperative way of handling the first use-case (as it is developed for versions of Java that lack first-class functions). The 2nd and 3rd use-cases above have as few methods as possible (or and transform(..)). Leightweight API that can achieve pretty much the same things, in the same amount of code.

In fact, having a functional approach for the main use-case is not necessarily good - the point of having an Optional type is not to be able to work functionally with it - the point is to be made aware that the value might not be there. I'm not saying to get rid of it in scala and Java8, but then maybe .isPresent() and .get() could be reconsidered.

Bottom-line is - it is hard to design APIs. Even a simple thing as an optional type has a lot of aspects to consider in terms of primary and secondary usa-cases, and whether convenience methods are needed, or they add unnecessary complexity to the API and can instead be handled in a different (not necessarily more verbose) way.

And finally - use optional types when you can possibly return null - NPEs are easy to debug and fix, but are easy to miss and may happen at the wrong moment.

Published at DZone with permission of Bozhidar Bozhanov, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)



Pierre-yves Saumont replied on Wed, 2014/03/26 - 5:13am

If the point is only "to be made aware that the value might not be there", you don't need a monad for this. You just need to know (from the specification) that a method may return null, and you just have to test the result for null.

What you are saying is that if you don't know what the Option monad is, you don't need it. In that sense, you are right.

So, the question is: "Is the Optional class in Java a monad". If you can answer this question, you are able to decide what Option/Optional implementation is the best. Otherwise, you probably should not be using it.

By the way, the Option monad is important in order to transform partial functions into total ones, in order to be able to compose them in any cases, even when they do  not return a value (or return null). Partial functions do not compose when they have no result.

From this, you can understand two things:

  • The best Option implementation (as a monad) of the three is obviously the Scala one. 
  • The Try monad would have been much more useful, since most partial functions produce an Exception rather than just a null value. Being able to compose functions when then produce exceptions is much more useful than composing functions producing null.
The heart of the problem is that you will have very little benefit from using Option/Optional if not adopting functional programing style. And developers using functional programing style have been using Option and Try for long (having developed their own implementation or using a functional library such as Functional Java).

Daniel Sobral replied on Wed, 2014/03/26 - 10:22am

You cannot implement flatMap in terms of map, and there's a simple, common use case for flatMap: chaining multiple Optional values required for a single computation.

I might also add that foreach and for loop in Scala _are_ the same thing, and the "complexity" of having both (or using foreach for just one or two values) is offset by the fact that everything offering a "foreach" method can use the same for loop syntax.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.