Introduction
Optionals were added in Java 8 and got some extra methods with Java 9. In this post I will cover how to use Optionals in your code.
Creating an Optional
The first step is to create an Optional instance. There are several ways to do this, depending on your needs. If you need am empty optional you can do the following:
|
|
The empty()
method creates an Optional that contains no value.
To create an optional that hold a value you can use the of method:
|
|
The of()
method creates an Optional from a value that you know is not null. If you try to pass a null value to of()
,
it will throw a NullPointerException
. This prevents you from creating an optional without a value.
If there is a chance that the value might be null you can use the ofNullable
method instead like so:
|
|
This will create an Optional from the given value and allowed to be null. When the instance is null
the optional will be empty.
get() a value from Optional
To get a value out the optional you can use the get()
method like this:
|
|
Calling get()
on an empty Optional will throw a NoSuchElementException
. Always check that an Optional contains a value with isPresent()
before calling get()
to prevent
getting an exception.
Checking if a value is present
When you are using Optionals you want to check if they hold a value before you get()
it out of it. To check if a value is
present you can use the isPresent()
method like so:
|
|
In the example isPresent()
returns true because the Optional contains “Hello”. If the Optional were empty, isPresent()
would return false
.
It's important to always check isPresent()
before calling get()
to retrieve the contained value. If you call get()
on an
empty Optional, it will throw a NoSuchElementException
. By checking isPresent()
first, you can avoid this exception and handle a null/empty
value in a better way.
Conditional Actions
You don't always have to create if statements when working with optionals. You can also pass a lambda that will run depending on whether a value is present or not.
ifPresent()
The ifPresent()
method lets you execute a some code only if the Optional contains a value:
|
|
In the previous example, the lambda expression passed to ifPresent()
will only be executed if opt
contains a value. If opt
is empty, nothing will happen.
This is way cleaner that having to create an if statement each time.
ifPresentOrElse()
Sometimes you'll want to take one action if an Optional contains a value and a different one when it doesn't. The ifPresentOrElse()
method lets you define an action for both
of these situations:
|
|
In this example, opt
is empty, the first lambda will be skipped, and the second one will be executed, printing “No value present”.
OrElse
With these methods you can have a default value in cases the Optional is empty.
orElse()
With orElse()
you can define a default value in cases where the optional is empty. If the optional has a value you will get one,
or the default when it is empty.
|
|
In the previous example, since opt
is empty, orElse()
will return the default value “Default Value”. If opt
contained
a value, orElse()
would return that value instead.
⚠️ one thing to watch out for: the argument you pass to
orElse()
is always evaluated, even if the Optional contains a value. If you have a computationally expensive default value, consider usingorElseGet()
instead.
orElseGet()
Like orElse()
, orElseGet()
returns a value if present, or a default value if the Optional is empty. The difference is that orElseGet()
takes a Supplier function to generate the default value:
|
|
The Supplier
passed to orElseGet()
is only called if the Optional is empty. This can be more efficient than orElse()
if the default value is expensive to compute.
orElseThrow()
In some cases, you might want to raise an exception if an Optional is empty, rather than providing a default value. In those cases
you can use orElseThrow()
like this:
|
|
Since opt
is empty, orElseThrow()
will throw the exception produced by the given Supplier function. If opt
contained a value, orElseThrow()
would return that value instead.
There's also a no-arg version of orElseThrow()
that throws a NoSuchElementException
if the Optional is empty:
|
|
Using orElseThrow()
is a good way to ensure that your code fails fast if an expected value is missing, rather than continuing with a null value and potentially causing a NullPointerException
later on.
or()
The or()
takes a Supplier that produces another Optional:
|
|
If opt
contains a value, or()
simply returns opt
. But if opt
is empty, or()
returns a new Optional. In the example, that's an Optional with “Fallback Value”.
This can be useful when you have a chain of fallback options, each of which might or might not produce a value. For example:
|
|
If firstOption
contains a value, that value will be returned. If not, secondOption
will be checked, then thirdOption
, and finally the default value “Default Value” will be used if all the options are empty.
Mapping Values
Optionals provide several methods for transforming and filtering the values they contain.
map()
The map()
method applies a function to the contained value (if present) and returns a new Optional containing the result:
|
|
map()
applies the toLowerCase()
method to “HELLO”, and returns a new Optional containing the result “hello”. If opt
were empty, map()
would simply return an empty Optional.
This is handy when you want to transform a value without having to deal with null values. The function you pass to map()
must return a non-Optional value. If you have a function that returns an Optional, you'll need to use flatMap()
instead.
flatMap()
Like map(), flatMap()
transforms the value in an Optional by applying a function. The difference is that the function passed to flatMap()
must return an Optional itself:
|
|
Here, the lambda passed to flatMap()
takes the String “HELLO”, converts it to lowercase, and returns a new Optional containing the result. If opt were empty, flatMap()
would return an empty Optional.
If the function passed to flatMap()
returns an empty Optional, the result of flatMap()
will be an empty Optional. This is useful for chaining together Optional-producing operations without having to check for emptiness at each step.
If you didn't use flatMap()
you would get an Optional inside another Optional.
filter()
To check whether the value in an Optional satisfies some condition. you can use filter()
:
|
|
filter()
checks whether the String has a length greater than 5. Since “Hello” has a length of 5, the predicate returns false, and filter()
returns an empty Optional.
If the predicate returns true, filter()
returns the Optional. If the Optional is empty to begin with, filter()
simply returns an empty Optional.
Converting to Stream
The stream()
method lets you convert an Optional into a Stream:
|
|
If opt
contains a value, the Stream will contain that single value. If opt
is empty, the Stream will also be empty.
This can be useful when you want to perform Stream operations on the value in an Optional, or when you have a Stream of Optionals and you want to flatten it into a Stream of values.
Conclusion
In this post, you have seen how to create Optionals, how to check if they contain values, how to extract those values, how to have default value, and how to transform and filter the values.