If-statements are all around us and a big amount of them are simply checking if a value is there or not.

If we now for a minute move away from this imperative way of thinking - why should we have to explicitly explain how to do a null check? Why can't we just let Java take care of the how so we can focus on the what?

That's exactly what Optional can do for us.

Optional is a container object that may or may not contain a non-null value.

To interact with the value, Optional offers a set of useful methods that abstract away the null checks.

This leaves us with more concise and declarative code that is focused on the details we care about.

Let's start coding

To get familiar with how to interact with Optional , consider the following.

We have a method - getRelevantArticleFor - that finds an article that is relevant for a given tag.

Optional<Article> article = getRelevantArticleFor("Java");

This method returns an Optional<Article> that may or may not contain an article depending on if a relevant article was found.

Now we want to be able to use this article, and to do so we're going to use Optional 's API.

Let’s start with a classic. If a relevant article was found - do some work.

Instead of using an if-statement to check if not null, we'll use ifPresent .

article.ifPresent(a -> print(a));

ifPresent is a higher-order function that takes a consumer function that describes what we want done if the value is present.

Moving on - let's look at a few options for fetching the actual article out from Optional .

First of all, Optional has a get function.

article.get();

The problem with get , is that it'll throw an exception if Optional is empty.

So, what else can we do?

orElse is another function for fetching the article, where you're given the chance to provide an alternative value.

article.orElse(getNewestArticle());

But, why fetch the alternative article before we’re sure we need it?

Instead, we could use a second option - orElseGet - which takes a supplier that is executed if Optional is empty.

article.orElseGet(() -> getNewestArticle());

Now that we've looked at functions that simply act based on the existence or non existence of Optional 's value, let's move to functions that changes value inside Optional .

If we have some requirements that the value needs to fulfill - say the relevant article must be less than a month old - we can use filter to check the value against a predicate.

article.filter(a -> newerThanAMonth(a));

If the value fails the predicate, it'll return an empty Optional .

Since filter returns an Optional , we can combine it with other functions in Optional 's API.

As an example, let’s combine filter and orElseGet to find a relevant article the last month, and if not found, return the newest article we got.

article.filter(a -> newerThanAMonth(a)) .orElseGet(() -> getNewestArticle());

Optional also offers the map function, allowing us to transform the value.

An example of this could be transforming an Optional containing a potential article to an Optional containing a potential title.

article.map(Article::getTitle);

Optional 's API also contain flatMap .

flatMap could be useful if objects wrapped by Optional also contains Optional properties.

To reason about this, let's say that our article has an Optional<Date> , holding the date when published. If the article yet hasn't been published, the Optional would be empty.

If we use the map function, we'll end up with a nested Optional .

Optional<Optional<Date>> published = article.map(Article::published);

This is not an ideal solution. So instead we could use flatMap to flatten the result.

Optional<Date> date = article.flatMap(Article::published);

A word of caution

Hopefully this post gives you some ideas about how you could use Optional in your code.