Java8 – How to use Optional ?

Java8 evolves with many features like Functional style programming, Lambda expressions, powerful stream API, parallel stream, IO and NIO, Default methods, etc. Optional type is one the small but important class added in java.util package. It is a cousin of scala.Option[T] and Data.Maybe in Haskell. Let’s explore it.

You are not real Java programmer if you have not deal with null pointer exception.Developers are often tired of Null pointer exceptions and its consequences.

optional-funny1

Let’s take an example to understand problems and how Optional helps to resolve it.

What is problem with Null check ?

If you have complex object Customer which has another complex object Address which has city attribute. If you want to retrieve city then

Customer customer = retrieved from API
customer.getAddress().getCity();

It might be possible that customer object or customer.getAddress() object returns null which result in Null pointer exception.

To overcome it, you can put null check like below and get somewhat rid of null pointer.

if(customer != null) {
if(customer.getAddress() != null) {
System.out.println("City :"+customer.getAddress().getCity());
}
}

The problems with above snippet are :

  • It quickly becomes very ugly due to the nested checks.
  • You need a lot of boilerplate code to make sure we don’t get a NullPointerException.
  • It’s just annoying that these checks get in the way of the business logic. In fact, they are decreasing the overall readability of our program.
  • It is an error-prone process if you forget to check that one property could be null?

Using null to represent the absence of a value is a wrong approach. What we need is a better way to model the absence and presence of a value.

Optional to resolve it ?

It is 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.

Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (return a default value if value not present) and ifPresent() (execute a block of code if the value is present).

  • public static <T> Optional<T> of(T value)

You can create Optional object from this method. This method will throw Null pointer exception if passed object is null.

Address address = customer.getAddress();
addressOptional = Optional.of(address);
  • public static <T> Optional<T> ofNullable(T value)

This method will give empty(not null) Optional object if passed value is null.If you are dealing with optional fields which might be null or not null then you should use this method.

  • public boolean isPresent()

This instance method returns true if value present otherwise false. This is method that you should always use for null check instead of !=. This way it gives opportunity to handle the action to deal with absence case.

  • public T get()

This method returns value of present else throw NoSuchElementException.

if(addressOptional.isPresent()) {
String city = addressOptional.get().getCity();
}
  • public T orElse(T other)

This is method returns the value if present, otherwise return other.

address = retrieved from API
Optional<Address> addressOptional = Optional.of(address);
Address returnedAddress = addressOptional.orElse(new Address());

Here, if address retrieved from API is null then orElse return empty address object else it will returns whatever retrieved from API.

How does Optional help with functional programming?

Before reading this section, take understanding of functional programming and lambda expressions.

  •  public T orElseGet(Supplier<? extends T> other)

Return the value if present, otherwise invoke other and return the result of that invocation. Supplier is functional interface which having only one method get().

addressOptional.orElseGet(() -> new Address("AHMEDABAD"));

This is same orElse where we are directly passing object to be return, here it is through Supplier interface.

  • public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X

Return the contained value, if present, otherwise throw an exception to be created by the provided supplier.

Address address = addressOptional.orElseThrow(AddressNotFound :: new);

It will throw AddressNotFound exception if addressOptional is empty else. This is catched exception so caller needs to handle it either by throwing or catching.

  •  public Optional<T> filter(Predicate<? super T> predicate)

If a value is present, and the value matches the given predicate, return an Optional describing the value, otherwise return an empty Optional.

Optional<Address> address = addressOptional.filter(
(Address ad) -> "Ahmedabad".equals(ad.getCity()));

This will return Optional only if value present and it city is equal to “Ahmedabad” otherwise it returns empty Optional.

  • public<U> Optional<U> map(Function<? super T, ? extends U> mapper)

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.

// non empty string map to its length we get the lenght as output (18)
Optional stringOptional = Optional.of( "Optional String" );
Optional sizeOptional = stringOptional.map( String::length ); //map from Optional to Optional
System.out.println( "size of string " + sizeOptional.orElse( 0 ) );
  • public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

If a value is present, apply the provided Optional bearing
mapping function to it, return that result, otherwise return an empty
Optional.  This method is similar to map,
but the provided mapper is one whose result is already an Optional,
and if invoked, flapMap does not wrap it with an additional
Optional.

public static void main(String[] args) {
Optional<String> s = Optional.of("input");
System.out.println(s.map(Test::getOutput));
System.out.println(s.flatMap(Test::getOutputOpt));
}

static Optional<String> getOutputOpt(String input) {
return input == null ? Optional.empty() : Optional.of("output for " + input);
}

static String getOutput(String input) {
 return input == null ? null : "output for " + input;
}

Optional is not meant to be a mechanism to avoid all types of null pointers. The mandatory input parameters of methods and constructors still have to be tested for example.

The purpose of Optional is not to replace every single null reference in your code base but rather to help design better APIs in which—just by reading the signature of a method—users can tell whether to expect an optional value. In addition, Optional forces you to actively unwrap an Optional to deal with the absence of a value; as a result, you protect your code against unintended null pointer exceptions.

Done. If you enjoyed this post, I’d be very grateful if you’d help it spread by emailing it to a friend, or sharing it on social media. Thank you!

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s