Google

May 22, 2014

Java 8 Optional class to alleviate some of the pains of unsightly null pointer checks and defensive coding

The most prevalent runtime exception (aka unchecked) exception in Java is the NullPointerException. You need to code defensively to avoid NullPointerException as shown below. Later, we will see how the class java.util.Optional that was introduced in Java 8 will alleviate this problem to some extent.

Pre Java 8 without the java.util.Optional class


public class Person {

 private String name;
 private int age;
 
 private HealthInsurance insurance; 
 
 //getters and setter
}


public class HealthInsurance {

 private String name;
 private Extra[] extras;

 //getters and setters
}


public class Extra {
      
 private String name;

 //getters and setters 
}


Now, here is the main class that invokes printExtras(Person person), where you need to check for null

public class PersonTest {

 public static void main(String[] args) {

  Person person1 = new Person();
  person1.setName("John");
  printExtras(person1);
  
  Person person2 = new Person();
  person2.setName("Peter");
  
  HealthInsurance healthIns = new HealthInsurance();
  Extra[] healthExtras = { new Extra("Physio"), new Extra("Optical"), new Extra("Chiro") };
  healthIns.setExtras(healthExtras);
  
  person2.setInsurance(healthIns);
  printExtras(person2);

 }

 private static void printExtras(Person person) {
  if (person != null && 
   person.getInsurance() != null 
   && person.getInsurance().getExtras() != null) {
   
   Extra[] extras = person.getInsurance().getExtras();
   for (Extra extra : extras) {
    System.out.println(extra.getName());
   }
  }

 }
}


In Java 8 with java.util.Optional class


Take note of the Optional class.
package com.java8.examples;

import java.util.Optional;

public class Person {
 
 private String name;
 private int age;
 private Optional<HealthInsurance> insurance = Optional.empty(); //default
 
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 
 public void setAge(int age) {
  this.age = age;
 }
 
 
 public Optional<HealthInsurance> getInsurance() {
  return insurance;
 }
 public void setInsurance(Optional<HealthInsurance> insurance) {
  this.insurance = insurance;
 }
}


package com.java8.examples;

import java.util.Optional;

public class  HealthInsurance{

 private String name;
 private Optional<Extra[]> extras = Optional.empty(); //default

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public Optional<Extra[]> getExtras() {
  return extras;
 }

 public void setExtras(Optional<Extra[]> extras) {
  this.extras = extras;
 }
}


package com.java8.examples;

public class Extra {

 private String name;

 public Extra(String name) {
  super();
  this.name = name;
 }

 public String getName() {
  return name;
 }
}


Finally, the main class that make use of the Optional.of methods, and the printExtras(Optional person) is much simpler with functional programming and lambda expressions.


package com.java8.examples;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

public class PersonTest {

 public static void main(String[] args) {

  Person person1 = new Person();
  person1.setName("John");

  Optional<Person> p1 = Optional.of(person1);
  printExtras(p1);

  Person person2 = new Person();
  person2.setName("Peter");

  // health ins and extras are supplied
  HealthInsurance healthIns = new HealthInsurance();
  Extra[] healthExtras = { new Extra("Physio"), new Extra("Optical"), new Extra("Chiro") };

  healthIns.setExtras(Optional.of(healthExtras));
  person2.setInsurance(Optional.of(healthIns));

  Optional<Person> p2 = Optional.of(person2);
  printExtras(p2);

 }

 private static void printExtras(Optional<Person> person) {
  person
      .flatMap(Person::getInsurance)
      .flatMap(HealthInsurance::getExtras)
      .ifPresent((p) -> {for(int i = 0; i < p.length; i++) {
                        System.out.println(p[i].getName());
                }
                        });
         
     }
}


Both approaches outputs

Physio
Optical
Chiro


Here are the convenient methods that the Optional class support

  • ifPresent( ):  returns true if a value is present in the optional.
  • get( ):  returns a reference to the item contained in the optional object, if present, otherwise throws a NoSuchElementException.
  • ifPresent(Consumer<T>consumer):  passes the optional value, if present, to the provided Consumer (lambda expression or method reference).
  • orElse(T other): returns the value, if present, otherwise returns the value in other.
  • orElseGet(Supplier<T> other):  returns the value if present, otherwise returns the value provided by the Supplier (lambda expression or method reference).
  • orElseThrow(Supplier<T> exceptionSupplier): returns the value if present, otherwise throws the exception provided by the Supplier (lambda expression or method reference)

Note:  In Java you cannot simply get rid of the null references that have historically existed, but before Java 8, you need to rely on your code and proper documentation to understand if a reference is optional. java.util.Optional<T> class has been added to deal with optional object references. The intention with the Optional class is not to replace every null-able reference, but to help in the creation of more robust APIs you could tell if  you can expect an optional reference by reading the signature of a method.

Labels: , ,

4 Comments:

Blogger Jatin Goyal said...

nice

12:39 PM, May 22, 2014  
Blogger Unknown said...

Thanks Jatin.

2:07 PM, May 22, 2014  
Blogger Unknown said...

Great!

11:10 PM, May 22, 2014  
Blogger Unknown said...

Thanks Cassio.

11:21 PM, May 22, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home