Ernest Duodu Ernest is a developer at IDRSolutions. He focuses mainly on our JavaFX PDF Viewer implementation. He was a speaker at JavaOne 2014, where he did a joint session titled "Lessons learnt developing a NetBeans PDF viewer plugin in JavaFX". Aside programming, he also enjoys a wide variety of hobbies which includes sky-diving, photography, exercising and listening to music.

Java 8 Optional Explained in 5 minutes

2 min read

In my previous Java 8 series articles, we discussed Lambda Expression, Streams API, Default Methods and Method References., Repeating Annotations and Consumer Supplier. 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

Hopefully you have found this quick guide useful.

We now have a series of articles on what is new in Java 9:

IDRsolutions develop a Java PDF Viewer and SDK, an Adobe forms to HTML5 forms converter, a PDF to HTML5 converter and a Java ImageIO replacement. On the blog our team post anything interesting they learn about.

Ernest Duodu Ernest is a developer at IDRSolutions. He focuses mainly on our JavaFX PDF Viewer implementation. He was a speaker at JavaOne 2014, where he did a joint session titled "Lessons learnt developing a NetBeans PDF viewer plugin in JavaFX". Aside programming, he also enjoys a wide variety of hobbies which includes sky-diving, photography, exercising and listening to music.

6 Replies to “Java 8 Optional Explained in 5 minutes”

  1. Why is this better than checking for null prior to printing. It seems to me that we have just changed
    if (m.getStudent() != null)
    with
    if (m.getStudent().isPresent())

    So now we’re not polluting our codebase with null checks, we’re just polluting it with isPresent() checks. Is there some other benefit that I am missing here?

    1. What happens if you miss the !=null check? Results in a crash!

      If you are working with Optional properties, and try to access its value directly, it will throw compile time error forcing you to do .isPresent() check & use a .get() to unwrap the optional value.

      In a large codebase, this would be very handy since the properties used & the usage are implemented by different people at different time.

  2. I too can’t see the added value in the example, because null check seems to do the same. Various instance methods that do something or nothing depending on the value present would be much better.

    Another thing… When I saw the code, first thought was “ah, isn’t this default Eclipse javadoc template?”… then you left TODOs there too, do they make sense or did you just start writing code after them? Class Student doesn’t seem to represent a student, but rather a student count, then the line like private Optional students = Optional.empty(); is extremely confusing (singular vs plural). This all distracts from the final point made.

  3. PLEASE USE GENERICS!!!
    You cannot code anymore without making using of generics…
    🙂

Leave a Reply

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