Guava Optional Class Example

Problem with Null Pointers — using Guava’s Optional Class

Ever since I can remember NullPointerExceptions (NPEs) have been a source of frustration and problems in many of the projects I have been involved in, current project included. Primarily, due to the fact that null is ambiguous and does not relay to the developer or the user what a null is supposed to mean. For example, Hashmap.get(key) may return a null when the key is not found in the Hashmap but it may also return a null if the key exists but the value is null. Throughout the years we have developed our own classes that handle this ambiguity for us, but by making use of Guava’s Optional class we have the added advantage of leveraging the mass of the open source community both in terms of testing capability and the sheer number of folks using Google’s Guava code base.

“I call it my billion-dollar mistake” — Sir Tony Hoare, on his invention of the null reference

Guava’s Optional class

You will use Guava’s Optional class anywhere you might expect to use a null object. The Optional class itself does not have any constructors and instead uses three static methods for creating an instance of that class. Optional.of(T) assumes the value of T will not be null, if it is it will fail fast and throw a NullPointerException (NPE).

The second available static method for creating an instance Optional is the Optional.fromNullable(T) which works very similar to Optional.of(T) except that it will work with both null and non-null values and returns Optional instance containing the wrapped contents of the reference T if it was non-null value, otherwise it returns Optional.absent().

The third static method for creating an instance Optional is the Optional.absent(). This returns an Optional instance with no reference contained in it and is mostly used when you know that the value being returned will be null.

By using Guava’s Optional class we reduce and replace null references with non-null values. The instance of Optional, will contain a non-null T reference (which is to say, the reference is “present”). Or the Optional instance will contain nothing (which is to say the Optional, is “absent”). However, at no point will the Guava’s Optional contain null. The point of using Optional, is to make the user of your API or class to think about the possibility of the value not being present.

Static Methods to Create Instance of Optional

#MethodDescription
1Optional.of(T)Assumes the value of T will not be null, if it is it will fail fast and throw a NullPointerException (NPE)
2Optional.fromNullable(T)Accepts both null and non-null values and returns Optional instance containing the wrapped contents of the reference T if it was non-null value, otherwise it returns Optional.absent()
3Optional.absent()Return an absent Optional of the type specified

Methods available to Optional instance

As you will see in the examples below, once you have an instance of Optional you can use instance methods described below.

#MethodDescription
1boolean isPresent()This method returns true if the Optional instance contains (non-null) reference
2T get()Returns the contained instance of T, provided it exists. Otherwise, it throws an IllegalStateException.
3T or(X)Returns the contained instance of T if it exists, otherwise it returns the default value specified in X.
4T orNull()Returns the contained instance of T if it exists, otherwise it returns null.
5Set asSet()Returns an immutable singleton Set containing the instance in this Optional, otherwise it will return an empty immutable set.

Sample Usage

Using isPresent() Method

if (optionalPerson.isPresent()) {
  System.out.println("Instance optionalPerson has a value present...");
}
// Returns true is instance contains (non-null) value
System.out.println("isPresent...: " + optionalPerson.isPresent());  

optionalPerson.isPresent() Output

Instance optionalPerson has a value present...
isPresent...: true

Using get() Method

Integer myFileID = new Integer(10);
Optional<Integer> fileId = Optional.fromNullable(myFileID);

if (fileId.isPresent()) {
  System.out.println("Current fileID is: " + fileId.get());
}

fileId.get() Output

Current fileID is: 10

Using or() Method

...
Optional<String> myFile2 = Optional.fromNullable(filename2);
String defFileName2 = myFile2.or("hello.txt");

// Using Java Ternary Operator is the equivalent
String defaultFileName2 = (filename2 != null) ? filename2 : "hello.txt";

System.out.println("defaultFileName2...: " + defaultFileName2);
System.out.println("defFileName2.......: " + defFileName2);

myFile2.or(“hello.txt”) Output

defaultFileName2...: picture.png
defFileName2.......: picture.png

Using orNull() Method

Integer myFileID = new Integer(10);
Optional<Integer> fileId = Optional.fromNullable(myFileID);
Optional<Integer> fileIdNull= Optional.fromNullable(myFileIDNull);

if (fileId.isPresent()) {
	System.out.println("Current fileID is: " + fileId.get());
}
System.out.println("Current fileIDNull is: " + fileIdNull.orNull());

orNull() Output

Current fileID is: 10
Current fileIDNull is: null

Project Structure

GuavaOptionalProject

GuavaOptionalExample.java

package com.avaldes.tutorial;

import com.avaldes.model.Person;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class GuavaOptionalExample {
  public static void main(String[] args) throws JsonProcessingException {
    
    // Creating Person object using setter methods not in the constructor
    Person p = new Person();
    p.setFirstName("John");
    p.setLastName("Miller");
    p.setAge(35);
    p.setGender("M");
    p.setStreetAddress1("100 Main Street");
    p.setCity("Fort Lauderdale");
    p.setStateProvince("Florida");
    p.setCountryName("United States");
    
    Person p1 = new Person("Elizabeth", "Jackson", 13, "F", "32 Oak Street", 
                       "Apt3C", "Waterloo", "Alabama", "United States", null);
    
    System.out.println("-------Java Object -- toString()---------");
    System.out.println(p.toString());
    System.out.println(p1.toString());
    
    System.out.println("--------- JSON ---------");
    ObjectMapper jsonMapper = new ObjectMapper();
    System.out.println(jsonMapper.writeValueAsString(p));
    System.out.println(jsonMapper.writeValueAsString(p1));
    
    System.out.println("------ JSON PRETTY PRINT -------");
    jsonMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
    System.out.println(jsonMapper.writeValueAsString(p));
    System.out.println(jsonMapper.writeValueAsString(p1));
  }
}

Output

-------Java Object -- toString()---------
Person [firstName=John, lastName=Miller, age=35, streetAddress1=100 Main Street, streetAddress2=Optional.absent(), city=Fort Lauderdale, stateProvince=Florida, countryName=United States, children=Optional.absent()]
Person [firstName=Elizabeth, lastName=Jackson, age=13, streetAddress1=32 Oak Street, streetAddress2=Optional.of(Apt3C), city=Waterloo, stateProvince=Alabama, countryName=United States, children=Optional.absent()]
--------- JSON ---------
{"firstName":"John","lastName":"Miller","age":35,"gender":"M","streetAddress1":"100 Main Street","streetAddress2":{"present":false},"city":"Fort Lauderdale","stateProvince":"Florida","countryName":"United States","children":{"present":false}}
{"firstName":"Elizabeth","lastName":"Jackson","age":13,"gender":"F","streetAddress1":"32 Oak Street","streetAddress2":{"present":true},"city":"Waterloo","stateProvince":"Alabama","countryName":"United States","children":{"present":false}}
------ JSON PRETTY PRINT -------
{
  "firstName" : "John",
  "lastName" : "Miller",
  "age" : 35,
  "gender" : "M",
  "streetAddress1" : "100 Main Street",
  "streetAddress2" : {
    "present" : false
  },
  "city" : "Fort Lauderdale",
  "stateProvince" : "Florida",
  "countryName" : "United States",
  "children" : {
    "present" : false
  }
}
{
  "firstName" : "Elizabeth",
  "lastName" : "Jackson",
  "age" : 13,
  "gender" : "F",
  "streetAddress1" : "32 Oak Street",
  "streetAddress2" : {
    "present" : true
  },
  "city" : "Waterloo",
  "stateProvince" : "Alabama",
  "countryName" : "United States",
  "children" : {
    "present" : false
  }
}

JavaNullCaseExamples.java

package com.avaldes.tutorial;
 
import java.util.HashMap;
 
import com.avaldes.model.Person;
import com.avaldes.util.PersonMapper;
import com.google.common.base.Optional;
 
public class JavaNullCaseExamples {
  public static void main(String[] args) {
    String filename1 = null;
    Optional<String> myFile1 = Optional.fromNullable(filename1);
    String filename2 = "picture.png";
    Optional<String> myFile2 = Optional.fromNullable(filename2);
     
    String defaultFileName1 = (filename1 != null) ? filename1 : "hello.txt";
    String defFileName1 = myFile1.or("hello.txt");
     
    String defaultFileName2 = (filename2 != null) ? filename2 : "hello.txt";
    String defFileName2 = myFile2.or("hello.txt");
     
    System.out.println("defaultFileName1...: " + defaultFileName1);
    System.out.println("defFileName1.......: " + defFileName1);
     
    System.out.println("defaultFileName2...: " + defaultFileName2);
    System.out.println("defFileName2.......: " + defFileName2);
      
    //----Implementation without Guava's Optional Class
    HashMap <Integer,Person> map = new HashMap<Integer,Person>();
    Person p1 = new Person("Elizabeth", "Jackson", 27, "F", "32 Oak Street", 
              "Apt3C", "Waterloo", "Alabama", "United States", null);
    Person p3 = new Person("Patrick", "Kilby", 42, "M", "192 Main Street", 
              null, "Winston", "Virgina", "United States", null);
    Person p4 = null;
     
    map.put(1, p1);
    map.put(3, p3);
    map.put(4, p4);
     
    System.out.println("\n================================================");
    System.out.println("Key is 1, value=" + map.get(1));
    // Key #2 does not exist, will return null
    System.out.println("Key is 2, value=" + map.get(2));
    System.out.println("Key is 3, value=" + map.get(3));
    // Key #4 value is absent, will return null
    System.out.println("Key is 4, value=" + map.get(4));
     
    PersonMapper pmap = new PersonMapper();
    pmap.put(1, p1);
    pmap.put(3, p3);
    pmap.put(4, p4);
     
    System.out.println("\n================================================");
    System.out.println("Key is 1, value = " + pmap.get(1)); 
    // Key #2 does not exist, will return null
    System.out.println("Key is 2, value = " + pmap.get(2)); 
    System.out.println("Key is 3, value = " + pmap.get(3));
    // Key #4 value is absent, will return null
    System.out.println("Key is 4, value = " + pmap.get(4));
     
    System.out.println("\n=[ Get Key==1, Check for Presence, orNull]======");
    Optional<Person> optionalPerson1 = pmap.get(1);
    System.out.println("Key is 1, isPresent=" + optionalPerson1.isPresent());
    System.out.println("Key is 1, value=" + optionalPerson1);
    System.out.println("Key is 1, orNull=" + optionalPerson1.orNull());
     
    System.out.println("\n=[ Get Key==2, Check for Presence, orNull]======");
    Optional<Person> optionalPerson2 = pmap.get(2);
    System.out.println("Key is 2, isPresent=" + optionalPerson2.isPresent());
    System.out.println("Key is 2, value=" + optionalPerson2);
    System.out.println("Key is 2, orNull=" + optionalPerson2.orNull());
 
    System.out.println("\n=[ Get Key==4, Check for Presence, orNull]======");
    Optional<Person> optionalPerson4 = pmap.get(4);
    System.out.println("Key is 4, isPresent=" + optionalPerson4.isPresent());
    System.out.println("Key is 4, value=" + optionalPerson4);
    System.out.println("Key is 4, orNull=" + optionalPerson4.orNull());
  }
}

Output

defaultFileName1...: hello.txt
defFileName1.......: hello.txt
defaultFileName2...: picture.png
defFileName2.......: picture.png

================================================
Key is 1, value=Person [firstName=Elizabeth, lastName=Jackson, age=27, streetAddress1=32 Oak Street, streetAddress2=Optional.of(Apt3C), city=Waterloo, stateProvince=Alabama, countryName=United States, children=Optional.absent()]
Key is 2, value=null
Key is 3, value=Person [firstName=Patrick, lastName=Kilby, age=42, streetAddress1=192 Main Street, streetAddress2=Optional.absent(), city=Winston, stateProvince=Virgina, countryName=United States, children=Optional.absent()]
Key is 4, value=null

================================================
Key is 1, value = Optional.of(Person [firstName=Elizabeth, lastName=Jackson, age=27, streetAddress1=32 Oak Street, streetAddress2=Optional.of(Apt3C), city=Waterloo, stateProvince=Alabama, countryName=United States, children=Optional.absent()])
Key is 2, value = Optional.absent()
Key is 3, value = Optional.of(Person [firstName=Patrick, lastName=Kilby, age=42, streetAddress1=192 Main Street, streetAddress2=Optional.absent(), city=Winston, stateProvince=Virgina, countryName=United States, children=Optional.absent()])
Key is 4, value = Optional.absent()

=[ Get Key==1, Check for Presence, orNull]==================
Key is 1, isPresent = true
Key is 1, value = Optional.of(Person [firstName=Elizabeth, lastName=Jackson, age=27, streetAddress1=32 Oak Street, streetAddress2=Optional.of(Apt3C), city=Waterloo, stateProvince=Alabama, countryName=United States, children=Optional.absent()])
Key is 1, orNull = Person [firstName=Elizabeth, lastName=Jackson, age=27, streetAddress1=32 Oak Street, streetAddress2=Optional.of(Apt3C), city=Waterloo, stateProvince=Alabama, countryName=United States, children=Optional.absent()]

=[ Get Key==2, Check for Presence, orNull]==================
Key is 2, isPresent = false
Key is 2, value = Optional.absent()
Key is 2, orNull = null

=[ Get Key==4, Check for Presence, orNull]==================
Key is 4, isPresent = false
Key is 4, value = Optional.absent()
Key is 4, orNull = null

Testing Java Using Nulls vs Guava Optional(MapExamples.java)

package com.avaldes.tutorial;

import static com.google.common.base.Strings.emptyToNull;

import java.util.HashMap;

import com.google.common.base.Optional;

public class MapExamples {
  
  public static void main(String[] args)  {
    HashMap<String, String> myMap = new HashMap<String, String>();

    myMap.put("Amaury", "Valdes");
    myMap.put("Christy", "Smith");
    myMap.put("", "Jackson");
    myMap.put("John", "Angeline");
    myMap.put(null, null);
    myMap.put("Bill", "Stanley");
    myMap.put("Hailey", null);
    myMap.put("Stacy", "Newmann");
    myMap.put("Kimmie", "");
    
    displayValuesUsingJavaNulls(myMap);
    displayValuesUsingGuavaOptional(myMap);
  }
  
  public static void displayValuesUsingJavaNulls(HashMap<String, String> myMap) {
    System.out.println("-------[ displayValuesUsingJavaNulls ]-------");
    for (String name : myMap.keySet()) {
      String value = myMap.get(name);
      if (name == null || name.isEmpty()) {
        System.out.print("Key: is empty or not available...");
      } else {
        System.out.print("Key: " + name);
      }
      if (value == null || value.isEmpty()) {
        System.out.println(", Value: is empty or not available...");
      } else {
        System.out.println(", Value: " + value);
      }
    }
  }

  public static void displayValuesUsingGuavaOptional(HashMap<String, String> myMap) {
    System.out.println("-------[ displayValuesUsingGuavaOptional ]-------");
    for (String name : myMap.keySet()) {
      Optional<String> optionalKey = Optional.fromNullable(emptyToNull(name));
      Optional<String> optionalValue = Optional.fromNullable(emptyToNull(myMap.get(name)));
      System.out.println("Key: " + optionalKey.or("is empty or not available...") 
          + ", Value: " + optionalValue.or("is empty or not available..."));
    }
  }
}

Output

-------[ displayValuesUsingJavaNulls ]-------
Key: is empty or not available..., Value: is empty or not available...
Key: is empty or not available..., Value: Jackson
Key: Bill, Value: Stanley
Key: Hailey, Value: is empty or not available...
Key: Kimmie, Value: is empty or not available...
Key: Christy, Value: Smith
Key: Amaury, Value: Valdes
Key: John, Value: Angeline
Key: Stacy, Value: Newmann
-------[ displayValuesUsingGuavaOptional ]-------
Key: is empty or not available..., Value: is empty or not available...
Key: is empty or not available..., Value: Jackson
Key: Bill, Value: Stanley
Key: Hailey, Value: is empty or not available...
Key: Kimmie, Value: is empty or not available...
Key: Christy, Value: Smith
Key: Amaury, Value: Valdes
Key: John, Value: Angeline
Key: Stacy, Value: Newmann

Testing Java Using Nulls vs Guava Optional(ArrayListExamples.java)

package com.avaldes.tutorial;

import java.util.ArrayList;
import java.util.List;

import com.google.common.base.Optional;
import static com.google.common.base.Strings.emptyToNull;

public class ArrayListExamples {
  public static void main(String[] args)  {
    List<String> myList = new ArrayList<String>();
    myList.add("Amaury");
    myList.add("Christy");
    myList.add("John");
    myList.add(null);
    myList.add("Bill");
    myList.add("");
    myList.add("Stacy");
    
    displayValuesUsingJavaNulls(myList);
    displayValuesUsingGuavaOptional(myList);
  }
  
  public static void displayValuesUsingJavaNulls(List<String> myList) {
    System.out.println("-------[ displayValuesUsingJavaNulls ]-------");
    for (String name: myList) {
      if (name == null || name.isEmpty()) {
        System.out.println("Name: Value is empty or not available...");
      } else {
        System.out.println("Name: " + name);
      }
    }
  }

  public static void displayValuesUsingGuavaOptional(List<String> myList) {
    System.out.println("-------[ displayValuesUsingGuavaOptional ]-------");
    for (String name: myList) {
      Optional<String> optionalName = Optional.fromNullable(emptyToNull(name));
      System.out.println("Name: " + 
				optionalName.or("Name: Value is empty or not available..."));
    }
  }
}

Output

-------[ displayValuesUsingJavaNulls ]-------
Name: Amaury
Name: Christy
Name: John
Name: Value is empty or not available...
Name: Bill
Name: Value is empty or not available...
Name: Stacy
-------[ displayValuesUsingGuavaOptional ]-------
Name: Amaury
Name: Christy
Name: John
Name: Name: Value is empty or not available...
Name: Bill
Name: Name: Value is empty or not available...
Name: Stacy

Person.java

package com.avaldes.model;

import java.util.List;

import com.google.common.base.Optional;

public class Person {
  private String firstName;
  private String lastName;
  private int age;
  private String gender;
  private String streetAddress1;
  private String streetAddress2;
  private String city;
  private String stateProvince;
  private String countryName;
  private List<Person> children;

  public Person() {}
  
  public Person(String firstName, String lastName, int age, 
      String gender, String streetAddress1, String streetAddress2, 
      String city, String stateProvince, String countryName, 
      List<Person> children) {

    super();
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.gender = gender;
    this.streetAddress1 = streetAddress1;
    this.streetAddress2 = streetAddress2;
    this.city = city;
    this.stateProvince = stateProvince;
    this.countryName = countryName;
    this.children = children;
  }
  
  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public String getGender() {
    return gender;
  }

  public void setGender(String gender) {
    this.gender = gender;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public String getStreetAddress1() {
    return streetAddress1;
  }

  public void setStreetAddress1(String streetAddress1) {
    this.streetAddress1 = streetAddress1;
  }

  public Optional<String> getStreetAddress2() {
    return Optional.fromNullable(streetAddress2);
  }

  public void setStreetAddress2(String streetAddress2) {
    this.streetAddress2 = streetAddress2;
  }

  public String getCity() {
    return city;
  }

  public void setCity(String city) {
    this.city = city;
  }

  public String getStateProvince() {
    return stateProvince;
  }

  public void setStateProvince(String stateProvince) {
    this.stateProvince = stateProvince;
  }

  public String getCountryName() {
    return countryName;
  }

  public void setCountryName(String countryName) {
    this.countryName = countryName;
  }

  public Optional<List<Person>> getChildren() {
    return Optional.fromNullable(children);
  }

  public void setChildren(List<Person> children) {
    this.children = children;
  }

  @Override
  public String toString() {
    return "Person [firstName=" + firstName + ", lastName=" + lastName 
        + ", age=" + age + ", streetAddress1=" + streetAddress1 
        + ", streetAddress2=" + getStreetAddress2() + ", city=" + city 
        + ", stateProvince=" + stateProvince + ", countryName=" 
        + countryName + ", children=" + getChildren() + "]";
  }
}

PersonMapper.java

package com.avaldes.util;

import java.util.HashMap;
import com.avaldes.model.Person;
import com.google.common.base.Optional;

public class PersonMapper {
  private HashMap<Integer, Person> hmap = new HashMap<Integer, Person>();
  
  public PersonMapper() {}
  
  public void put(Integer key, Person value) {
    Person person = value;
    hmap.put(key, person);
  }
  
  public Optional<Person> get(Integer key){
    Optional<Person> person = Optional.fromNullable(hmap.get(key));
    return person;
  }
} 

That’s It!

I hope you enjoyed this tutorial. It was certainly a lot of fun putting it together and testing it out. Please continue to share the love and like us so that we can continue bringing you quality tutorials. Happy Coding!!!

GuavaOptionalClass

Please Share Us on Social Media

Facebooktwittergoogle_plusredditpinterestlinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *