Java 8 Optional Example
In this article, we are going to show how to use the new Java 8 Optional – java.util.Optional
class.
1. Introduction
The null reference is a very common problem in Java, everybody got once a NullPointerException
because some variable or input parameter was not properly validated. In Java, null, can have a logical value and a meaning; so it is important to take it into consideration and do not ignore it.
With the introduction of java.util.Optional
in Java 8, several new possibilities for handling this problematic are available.
The new class is based on the analog functionalities in Haskell and Scala. It contains a value that can be present or not; if the value is not present, the Optional
instance is said to be empty.
All examples and code snippets listed have been done using Eclipse Luna version 4.4 and Java version 8 update 5 and can be downloaded at the end of this article.
2. Java 8 Optional
- empty() – Returns an empty Optional instance.
In order to create a Java 8 Optional we have to indicate what type of value is going to contain:
1 | Optional emptyOptional = Optional.empty(); |
The code above shows the creation of an empty optional, that is, its value is null or not initialized.
- get() – If a value is present, returns the value, otherwise throws NoSuchElementException.
In order to access the value of an optional we can use the method get()
; if we try to access the value of the example shown above, we would get the following exception.
01 02 03 04 05 06 07 08 09 10 | try { /* empty */ Optional emptyOptional = Optional.empty(); System.out.println( emptyOptional.get() ); } catch ( NoSuchElementException ex ) { System.out.println( "expected NoSuchElementException" ); //this is executed } |
The exception thrown is of the type java.util.NoSuchElementException
and means that the Optional
value is not initialized or null.
- of() – Returns an Optional describing the given non-null value.
In order to create a Java 8 Optional, we can use an existing object and pass it to the Optional
using the static method of()
:
1 | Optional nonEmptyOptional = Optional.of( str ); |
The object passed to the method of()
has to be different to null.
- ofNullable() – Returns an Optional describing the given value, if non-null, otherwise returns an empty Optional.
In case we want to offer the possibility of using potential null values, we can use ofNullable()
:
1 2 | String strNull = null ; Optional nullableOptional = Optional.ofNullable( strNull ); |
If we try to pass a null object to a Java 8 Optional using the method of()
we will get a NullPointerException
. At the end of this article there is a file to download with examples of all these possible combinations. In order to get the value of an Optional
you can use the get()
method as shown above. The problem of this method is that you can get a NullPointerException
if the value is not initialized. So, although it has some benefits is not solving all our problems.
There are several methods that can be used to retrieve the value of an Optional
and handle at the same time the possibility that it is a null reference. We are going to see some of them:
- orElse() – If a value is present, returns the value, otherwise returns other.
We can use the method orElse()
:
1 2 | Optional optionalCar = Optional.empty(); price = optionalCar.orElse( defaultCar ).getPrice(); |
In the code shown above we are trying to access to the price of a Car object, if the Car object is not initialize (or it is null) we will retrieve the price for the default car that we have defined before.
- orElseGet() – If a value is present, returns the value, otherwise returns the result produced by the supplying function.
The difference between orElse and orElseGet is that orElse() will always call the given function whether you want it or not, regardless of Optional.isPresent() value while orElseGet() will only call the given function when the Optional.isPresent() == false.
String n = Optional.of("Java").orElseGet(() -> getRandomName());
- orElseThrow() – If a value is present, returns the value, otherwise throws NoSuchElementException.
We can indicate the Optional
to throw an exception in case its value is null:
1 2 | Optional optionalCarNull = Optional.ofNullable( carNull ); optionalCarNull.orElseThrow( IllegalStateException:: new ); |
In this case, an IllegalStateException
will be thrown.
- orElseThrow(Supplier<? extends X> exceptionSupplier) – If a value is present, returns the value, otherwise throws an exception produced by the exception supplying function.
The difference between these two orElseThrow methods are the following:
T – orElseThrow():
- Returns the non-null value described by this Optional
- Throws NoSuchElementException – if no value is present
<X extends Throwable> T – orElseThrow():
- Returns the value, if present
- Throws X if no value is present and NullPointerException if no value is present and the exception supplying function is null
- Parameters: exceptionSupplier – the supplying function that produces an exception to be thrown
public T orElseThrow(Supplier exceptionSupplier) throws Throwable{ throw exceptionSupplier.get(); }
- or() – If a value is present, returns an Optional describing the value, otherwise returns an Optional produced by the supplying function. (added in java 9)
The difference between optional.or and optional.orElseGet is basically the return type but let’s see all of them in detail:
- Optional.orElseGet():
- The call to orElseGet returns the object T itself.
- throws NullPointerException if no value is present and the supplying function is null
- Use case: To fetch the value deterministically based on the supplied function.
- Optional.or():
- The Optional.or returns an Optional describing the value, otherwise returns an Optional produced by the supplying function
- throws NullPointerException if the supplying function is null or if the supplying function produces a null result.
- isPresent() – If a value is present, returns true, otherwise false.
There is the possibility to check directly if the value is initialized and not null:
1 2 3 4 5 | Optional stringToUse = Optional.of( "optional is there" ); if ( stringToUse.isPresent() ) { System.out.println( stringToUse.get() ); } |
- ifPresent() – If a value is present, performs the given action with the value, otherwise does nothing.
And also the option to execute actions directly when the value is present, in combination with Lambdas:
1 2 | Optional stringToUse = Optional.of( "optional is there" ); stringToUse.ifPresent( System.out::println ); |
The code shown above and the one before are doing exactly the same. I would prefer to use the second one. So these are some of the available methods to retrieve the values of an Optional
and to handle the null references.
- ifPresentOrElse() – If a value is present, performs the given action with the value, otherwise performs the given empty-based action.
Syntax:
ifPresentOrElse(action, emptyAction)
Parameters:
action – the action to be performed, if a value is present
emptyAction – the empty-based action to be performed, if no value is present
value.ifPresentOrElse( v -> successCount.incrAndGet(), EmptyOptCount::incrAndGet);
Now we are going to see the options that are offered in combination with Lambdas
:
- filter() – If a value is present, and the value matches the given predicate, returns an Optional describing the value, otherwise returns an empty Optional.
The Optional class contains a filter()
method that expects a Predicate
and returns an Optional
back if the Predicate
is true. Here are some examples:
01 02 03 04 05 06 07 08 09 10 11 | // if the value is not present Optional carOptionalEmpty = Optional.empty(); carOptionalEmpty.filter( x -> "250" .equals( x.getPrice() ) ).ifPresent( x -> System.out.println( x.getPrice() + " is ok!" ) ); // if the value does not pass the filter Optional carOptionalExpensive = Optional.of( new Car( "3333" ) ); carOptionalExpensive.filter( x -> "250" .equals( x.getPrice() ) ).ifPresent( x -> System.out.println( x.getPrice() + " is ok!" ) ); // if the value is present and does pass the filter Optional carOptionalOk = Optional.of( new Car( "250" ) ); carOptionalOk.filter( x -> "250" .equals( x.getPrice() ) ).ifPresent( x -> System.out.println( x.getPrice() + " is ok!" ) ); |
As we can see in the snippet above we do not have to take care of the null reference of the value, we can just apply our filters directly and the Optional
takes care of all the rest.
- map​() – If a value is present, returns an Optional describing (as if by ofNullable) the result of applying the given mapping function to the value, otherwise returns an empty Optional.
It is also very interesting the method map()
. This method “maps” or converts an Optional to another Optional using a Function as parameter. The mapping is only executed, if the result of the past Function is not null. Here are some examples:
1 2 3 4 5 6 7 8 9 | // non empty string map to its length -> we get the lenght as output (18) Optional stringOptional = Optional.of( "loooooooong string" ); Optional sizeOptional = stringOptional.map( String::length ); //map from Optional to Optional System.out.println( "size of string " + sizeOptional.orElse( 0 ) ); // empty string map to its length -> we get 0 as lenght Optional stringOptionalNull = Optional.ofNullable( null ); Optional sizeOptionalNull = stringOptionalNull.map( x -> x.length() ); // we can use Lambdas as we want System.out.println( "size of string " + sizeOptionalNull.orElse( 0 ) ); |
- flatMap() – If a value is present, returns the result of applying the given Optional-bearing mapping function to the value, otherwise returns an empty Optional.
Both map and flatMap can be applied to a Stream<T> and they both return a Stream<R>. When this function is applied to each element of this stream, it constructs a stream of new values. All the generated elements of these new streams are then again copied to a recent stream, which will then act as a return value of this method. The difference is that the map operation produces one output value for each input value, whereas the flatMap operation produces an arbitrary number (zero or more) values for each input value. This is reflected in the arguments to each operation. You can learn more about the flatMap() method in our Java 8 flatMap Example.
List filteL = listOfOptionals.stream()
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
.collect(Collectors.toList());
- hashCode() – Returns the hash code of the value, if present, otherwise zero if no value is present.
This method’s functionality is to digest the properties of an object into a single, 32-bit integer value. The hashCode() method should return a unique value for every object, and two objects must not have the same integer hash value, unless they are equal as the equals() method says. You can learn more about the flatMap() method in our Java hashCode method Example.
@Override public int hashCode() { return prefix.hashCode(); }
- stream() – If a value is present, returns a sequential Stream containing only that value, otherwise returns an empty Stream. (since Java 9)
This method converts an Optional into a Stream. If the Optional contains a value it will become a Stream of one element. If the Optional is empty, it will create an empty stream.
try { System.out.println("Stream:"); op.stream().forEach(System.out::println); } catch (Exception e) { System.out.println(e); }
Finally we should mention some simple methods.
- equals() – Indicates whether some other object is “equal to” this Optional.
Indicates whether some other object is “equal to” this Optional. The other object is considered equal if:
- it is also an Optional
- both instances have no value present
- the present values are “equal to” each other via equals().
It also overrides equals in class Object and returns true if the other object is “equal to” this object otherwise false.
System.out.println("Comparing first option" + " and second option: " + op1.equals(op2));
- toString() – Returns a non-empty string representation of this Optional suitable for debugging.
If a value is present the result must include its string representation in the result. Empty and present Optionals must be unambiguously differentiable.
String value = op.toString();
3. NullPointerException
For the ones that do not know what a NullPointerException
is, just try:
1 2 | String strNull0 = null ; System.out.println( strNull0.contains( "something" ) ); |
The code above would compile but we would get a warning like:
1 | Null pointer access: The variable strNull can only be null at this location |
In order to handle this, we can check and validate for null, or we can surround the block with a try catch
. In the following chapters we are going to see how to handle this issue using the new Optional
class.
4. Java Optional – Summary
And that’s it! In this article, we saw several examples about how to use the new Optional
class coming out in Java 8. This class allows us to manage null references in a clear and concise way and to handle the famous NullPointerException
more effectively. It is interesting to mention that there are also typified “optionals” for the types double
, int
and long
; they work in a similar way than the “generic” one, but their values are the ones of the correspondent type and the operations allowed are the ones related to the primitive type.
5. Additional Links
For more information about the Optional
class and other methods that we did not mention in this article or about Java 8 features in general, please visit:
- http://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html
- http://www.javacodegeeks.com/2014/05/java-8-features-tutorial.html
6. Download the Source Code
All examples from this article (and some more) can be downloaded in the following link: Java 8 Optional Example
Last Updated on May. 18th, 2020