Java 8 Optional

02 August 2014
By Gonçalo Marques
 
java java8
In this article we will cover Java 8 Optional.

Introduction

As the Optional documentation states, it's a container object which may or may not contain a non-null value. Google Guava library users may be already familiar with the Optional class since it was already included in the library.

The Optional goal is to correctly represent an eventually null value at an arbitrary application code location.

The usage of the Optional class will also lead to a lesser number of null pointer exceptions at application runtime. This assumption has lead to many discussions around the subject, since the Optional class will also throw an exception if we try to access its value while the value is null. The whole point of the Optional class is that developers will know that when they face an Optional - and consequently are forced to unwrap its value - they must account for the null value possibility (and of course, as it may already be clear, Optional also gives API developers a proper way of representing the null value possibility).

Let's see a comparison:

findUser returns a User instance

User findUser(Long userId);

If a developer is including some 3rd party API which contains the aforementioned findUser method, he may not immediately know what happens if he provides a userId that does not correspond to any user: will the method return a null reference? Will it throw an exception? Let's see the Optional variant of the same method:

findUser returns an Optional instance

Optional<User> findUser(Long userId);

Just by looking at the method signature it now becomes clear that the method may return an Optional containing a null value. Since we now have to explicitly unwrap the Optional contained instance, it's mandatory (and hard to forget or avoid) to account for the possibility of the wrapped value being a null reference.

The Optional

Let's see the Optional in practice:

Optional usage

String value = "Hello";
Optional<String> optionalString = Optional.of(value);

System.out.println(optionalString.isPresent()); // Will print true
System.out.println(optionalString.get()); // Will print "Hello"

// -----------------------------------------

String value = null;
Optional<String> optionalString = Optional.of(value); // Will throw NullPointerException

// -----------------------------------------

String value = null;
Optional<String> optionalString = Optional.ofNullable(value);

System.out.println(optionalString.isPresent()); // Will print false
System.out.println(optionalString.get()); // Will throw NoSuchElementException

// -----------------------------------------

String value = null;
Optional<String> optionalString = Optional.ofNullable(value);

System.out.println(optionalString.isPresent()); // Will print false
System.out.println(optionalString.orElse("other")); // Will print "other"

Optionals may also be used with Consumers and Suppliers:

(More info about Consumers and Suppliers in the following article: Java 8 Consumer and Supplier).

Optional usage with Consumers and Suppliers

String value = "Hello";
Optional<String> optionalString = Optional.of(value);

System.out.println(optionalString.isPresent()); // Will print true
optionalString.ifPresent((s) -> System.out.println(s.length())); // Will print 5

// -----------------------------------------

void run(){
  String value = null;
  Optional<String> optionalString = Optional.ofNullable(value);

  System.out.println(optionalString.isPresent()); // Will print false
  System.out.println(optionalString.orElseGet(Test::getString)); // Will print "Hello"
}

static String getString() {
  return "Hello";
}

Optionals may also be used with Predicates and Functions:

(More info about Predicates and Functions in the following article: Java 8 Predicates and Functions).

Optional usage with Predicates and Functions

String value = "Hello";
Optional<String> optionalString = Optional.ofNullable(value);
System.out.println(optionalString.isPresent()); // Will print true

Optional<String> otherOptional = optionalString.filter((s) -> s.length() > 4);
System.out.println(otherOptional.isPresent()); // Will print true
System.out.println(otherOptional.get()); // Will print "Hello"

Optional<String> anotherOptional = optionalString.filter((s) -> s.length() > 5);
System.out.println(anotherOptional.isPresent()); // Will print false

// -----------------------------------------

String value = "Hello";
Optional<String> optionalString = Optional.of(value);
System.out.println(optionalString.isPresent()); // Will print true

Optional<Integer> optionalInteger = optionalString.map((s) -> s.length());
System.out.println(optionalInteger.get()); // Will print 5

Optional<Integer> otherOptionalInteger = 
  optionalString.map((s) -> s.length() > 5 ? s.length() : null);
System.out.println(otherOptionalInteger.isPresent()); // Will print false

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: https://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: