Site iconJava PDF Blog

Java 8 Optional Explained in 5 minutes

At IDR Solutions we use Java 8 for the development of our products (a Java PDF Viewer and SDKPDF to HTML5 converter and a Java ImageIO replacement).  This time we will be looking at the Optional Class.

What is this Optional

It is simply a container that may contain some value or may contain a non-null value and it is primarily intended for use in streams. It has a method isPresent() which will return true when a value is present and a method called get() which will returns the value present. So this basically helps alleviate Null Pointer Exception.

You can already implement this functionality with null checks. It was added into Java8 to allow developers to write more ‘elegant’ code which is easier to read and can potentially be processed in parallel in Java.

Lets have a look at this code below:

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

/**
 *
 * 
 */public class Course {
    private  List modules = new ArrayList();
    public void addModule(Module module){
        modules.add(module);
    }
    public List getModules() {
        return modules;
    }
}

class Module{
     private Student students;
     private String moduleName;
     
     public Module(String moduleName){
         this.moduleName = moduleName;
    }
   

    public String getModuleName() {
        return moduleName;
    }

    public Student getStudent() {
        return students;
    }
    public void setStudents(Student students) {
        this.students = students;
    }
}

class Student{
    private int numberOfStudents;
    
    public Student(int number){
        this.numberOfStudents = number;
    }
    public int getNumberOfStudents() {
        return numberOfStudents;
    }

    public void setNumberOfStudents(int numberOfStudents) {
        this.numberOfStudents = numberOfStudents;
    }

    
      public static void main(String[] args) {
        // TODO code application logic here
        Course computerScience = new Course();
        Module algorithms = new Module("Algorithms");
        Student studentsOnAlgorithm = new Student(50);
        algorithms.setStudents(studentsOnAlgorithm);
        computerScience.addModule(algorithms);

       
        computerScience.getModules().stream().forEach((m) -> {
            System.out.println("Module ---> "+m.getModuleName() + " \n"+ m.getStudent().getNumberOfStudents()+" students take this module");
        });
    }
    
}

Output

Module —> Algorithms
50 students take this module

This code works perfect. Now lets say we have a module which has been discontinued teaching but still in the list of Course with no students attached to it.

  public static void main(String[] args) {
        // TODO code application logic here
        Course computerScience = new Course();
        Module algorithms = new Module("Algorithms");
        Student studentsOnAlgorithm = new Student(50);
        algorithms.setStudents(studentsOnAlgorithm);
        computerScience.addModule(algorithms);

        Module cancelledModules = new Module("Pascal");
        computerScience.addModule(cancelledModules);
        
       
         computerScience.getModules().stream().forEach((m) -> {
            System.out.println("Module ---> "+m.getModuleName() + " \n"+ m.getStudent().getNumberOfStudents()+" students take this module");
        });
    }
    
}

Output

Module —> Algorithms
50 students take this module

Exception in thread “main” java.lang.NullPointerException

Now lets Use the Optional Rectify the problem

public class Course {
    private  List modules = new ArrayList();
    public void addModule(Module module){
        modules.add(module);
    }
    public List  getModules() {
        return modules;
    }
}
 
class Module{
     private Optional students = Optional.empty();
     private String moduleName;
 
     public Module(String moduleName){
         this.moduleName = moduleName;
    }
 
 
    public String getModuleName() {
        return moduleName;
    }
 
    public Optional getStudent() {
        return students;
    }
    public void setStudents(Optional students) {
        this.students = students;
    }
}
 
class Student{
    private int numberOfStudents;
 
    public Student(int number){
        this.numberOfStudents = number;
    }
    public int getNumberOfStudents() {
        return numberOfStudents;
    }
 
    public void setNumberOfStudents(int numberOfStudents) {
        this.numberOfStudents = numberOfStudents;
    }
 
 
      public static void main(String[] args) {
        // TODO code application logic here
        Course computerScience = new Course();
        Module algorithms = new Module("Algorithms");
        Optional studentsOnAlgorithm = Optional.of(new Student(50));
        algorithms.setStudents(studentsOnAlgorithm);
        computerScience.addModule(algorithms);
 
        Module cancelledModules = new Module("Pascal");
        computerScience.addModule(cancelledModules);
 
        computerScience.getModules().stream().forEach((m) -> {
            if (m.getStudent().isPresent()) {
                System.out.println("Module ---> " + m.getModuleName() + " \n" + m.getStudent().get().getNumberOfStudents() + " students take this module");
            } else {
                System.out.println("Module ---> " + m.getModuleName() + "\nhas no students attached to it");
            }
        });
    }
 
}

Output

Module —> Algorithms
50 students take this module
Module —> Pascal
has no students attached to it

In the Module class, we replaced the Student with an empty Optional object and also replaced the getter and setter method to return and set Optional Objects.
Also in the body of the for loop, we used the m.getStudent().isPresent() if there is a value then we use the m.getStudent().get().getNumberOfStudents() to get the value available.

Convenient Instance Methods On Optional

filter(Predicate predicate)This will return a value present only if it is present and that it matches a given predicate otherwise it will return an empty optional
ifPresent()This will returns true if a value is present in the optional.
ifPresent(Consumer consumer)This will invoke the specified consumer with the value, only if the value is present otherwise do nothing.
get()This will returns the value in the Optional if present, otherwise throws NoSuchElementException.
orElse(T other)This will return the value, if present, otherwise returns the value in other.
orElseGet(Supplier other)This will return the value if present, otherwise invoke other and return the result of that invocation.
orElseThrow(Supplier exceptionSupplier)This will return the value, if present otherwise throw an exception created by the provided supplier

If you found this article useful, you may also be interested in our other Java8 posts on Lambda Expression, Streams API, Default MethodsMethod References and Repeating Annotations and Consumer Suppliers.

We also now have large collection of articles on what is new in other versions of Java, including Java9 , and Java13.