At IDR Solutions we use Java 8 for the development of our products (a Java PDF Viewer and SDK, PDF 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 Methods, Method 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.
Our software libraries allow you to
Convert PDF to HTML in Java |
Convert PDF Forms to HTML5 in Java |
Convert PDF Documents to an image in Java |
Work with PDF Documents in Java |
Read and Write AVIF, HEIC, WEBP and other image formats |
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?
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.
Matt, I have edited to post to make it much more clearer.
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.PLEASE USE GENERICS!!!
You cannot code anymore without making using of generics…
🙂
Thanks for the series of articles on Java 8. The test using ifPresent () is controversial and raises doubts about the optional’s value like above. I recommend the reading of the following article:
https://dzone.com/articles/optional-ispresent-is-bad-for-you