JavaData & JavaLearn to Work with Java Optional Classes

Learn to Work with Java Optional Classes

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

The interesting part of the utility classes (in the java.util package) is that they are not absolute necessary, yet they end up providing invaluable help in some form or manner. In fact, the utility classes are built to leverage productivity. Programmers can use and reuse them as and when required. The Optional class is one such class found in the java.util package. The class can be quite useful on occasions that suit the idea behind its existence. Let’s understand its utility and what impetus it has on Java programming.

An Overview of NullPointerException

Before going into the details of optional classes, let’s first understand a common Java exception, called NullPointerException. Most of us have encountered this exception many times while programming. A NullPointerException occurs when we try to use an object reference pointing to nothing or a null value. For example, in the following code, we have declared a primitive type variable such as an integer and later initialized it with a value.

int iVal;
iVal=20;

When the variable iVal is declared, Java automatically initializes it with 0. Later, when we assign a value of 20, the memory location referred by iVal is overwritten with the assigned value. Now, this is fine for a simple primitive type. See what happens when the variable is a reference types, such as

Person peter;
john=new Person("Peter Parker");

The variable peter here is a reference type and points to nothing, or a null value, in the first line. In the second line, with the new keyword a valid object is created in the heap that peter is the reference the variable points to.

Now, observe what happens if we try to access a member function of the Person class before creating the object with new keyword as follows.

Person peter;
// exception occurs here;
System.out.println(john.getName());
john=new Person("Peter Parker");

Voilà! A NullPointerException occurs. One way to eradicate this problem is to check if the object reference is really null before accessing it.

Person peter;
if(peter!=null)
   System.out.println(peter.getName());
else {
   john=new Person("Peter Parker");
   System.out.println(peter.getName());}

This may be fine when we are directly creating an object. But, there are situations where we do not create object directly, such as

void copyPersonData(Person p){
   // ...    
}

Here, we do not create a Person object directly. Instead, we rely on the reference type to send as an argument to the function call:

copyPersonData(new Person("Peter Parker"));

The function definition does not expect to receive a null value like this

copyPersonData(null);

However, to be on the safe side, we can always check on null value before accessing it. But, this is a cumbersome solution.

Here comes the utility of the Optional class that tries to provide a way out of this type of problem. Let’s get familiar with the trait that this API exhibits and what it has to offer.

Optional Class Library

Optional classes are introduced into the core Java API from version 1.8. There are basically four classes under the banner of optional classes: Optional<T>, OptionalInt, OptionalDouble, and OptionalLong, found in the java.util package.

Option1
Figure 1: Contents of the java.util package

All of them are declared as final; that means they cannot be extended by inheritance. Among them, Optional<T> is a generic classes. The number of member functions of each OptionalInt, OptionalDouble, and OptionalLong class is same by name and utility. The only variance is in their use of data types, such as OptionalDouble is concerned with double, OptionalInt with int, and OptionalLong with long data types.

Optional Classes as a Container

All optional classes provide a container for objects. The contained object may be present or may not be present. The problem of NullPointerException is completely evaded by being able to get a boolean true or false, according to the presence of a value or not in the container with the help of isPresent method. The get method returns the value if present; otherwise, NoSuchElementException is thrown.

NoSuchElementException is an extension of RuntimeException, thrown to indicate that the element being requested does not exist.

Optional<T> Class

Among all the optional classes, Optional<T> is the generic implementation. So, if we understand its implementation and how to use this class, understanding other optional classes such as OptionalDouble, OptionalInt, and OptionalLong should not be a problem. So, let’s explore this class alone.

  • The T in the Optional<T> represents the type of value stored.
  • There are only two choices, either the Optional<T> class can contain a value of type T or be empty.
  • This boolean choice is significant because it overcomes the problem of s null dereference. Conceptually, a null value, though, means no value yet it is a value in itself that references nowhere. Had it been not the case, we would not have been able to assign a null like this:
    String name=null;

    It’s a paradox! We are assigning something that refers to nothing … but how can you assign nothing to something when something that represents nothing is really something. (F/P)unny right?

  • Optional classes do not provide any constructor; instead, they define methods that really return optional objects. Also, there are methods to determine the presence of a value, fetch a value from the container, and so forth. Some common methods are as follows:
    • empty: Returns an empty instance.
    • equals: Indicates whether some other object is “equal to” this optional instance.
    • ifPresent: Have the specified consumer accept the value if a value is present; otherwise, do nothing.
    • isPresent(): Return true if there is a value present; otherwise, false.
    • of: Return an optional instance with the specified value present.
    • orElse: Return the value if present; otherwise, return other.
    • orElseGet: Return the value if present; otherwise, invoke other and return the result of that invocation.
    • orElseThrow: Return the contained value, if present; otherwise, throw an exception to be created by the provided supplier.
    • toString: Returns a string representation of the object.

Refer to Java API Documentation for more details.

Refer here for a code that compares the use of optional class and one without using it by Brian Goetz.

And, refer to the article Tired of Null Pointer Exceptions… by Raoul-Gabriel Urma for more details.

Conclusion

The whole point of the optional class is to provide the means to indicate the absence of a value rather than using null to mean no value present. There is no harm in using null to mean no value, but optional classes may be used to indicate an optional parameter of a class or pass an optional value to a function. So, the ultimate utility of this class boils down to three basic  principles: avoiding a null pointer, use optional to mean a optional parameter that may or may not contain a value, and lastly as a design goal to attain fluidity of code flow.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories