Welcome. Today we are taking an introductory look at the Java Optional Class. We will focus primarily on the Optional Class and what it is for. Then we will cover why it is useful and how to use it in our code. Finally, we wrap up with four hands examples of using the different types of Optional methods in our code.

What is Java the Optional Class?

The optional class is essentially a container object, which may or may not contain a non-nullable value.

Why should we use the Java Optional Class?

One of the biggest problems with Java is that when we create variables or methods with return types, our intent is unclear if the value of these will be null.

String name;
String getName();

void doSomething(){
    assertThat("My Name").isEqualTo(getName());
}

He is a simple example where we have a string name, a method that returns a string getName(), and then some method that tries to compare a string name equal to our getName(). The problem with this is name could be null and throw a NullPointerException at runtime. However,  just reading the code, we don’t know, for instance, if the name was ever instantiated or populated so it could contain a null value.

The code is very unclear on the intent of the name. Should it always be populated, or could the name be null?  How, as developers, do we know the name could be null? We don’t because the name is just specified as a name.

Unfortunately, this approach leaves it up to the developer to determine the intent of the variable if it can be null. This leads the developer to implement many null checks within their code.

if (name != null) { then do something... }

Primarily what do we do if the name is not known? What do we want to do with it? If we don’t know that name could be null, then when we try to use it, we will get a runtime exception all over the place when we try to use the name. This is where Optional comes in.

Why Is Java Optional useful?

When we use the optional class, we imply our intent that a variable or our method could potentially return a no result or a null. Because the Optional class gives us the ability to wrap our variables and methods. Telling the developer that this variable is optional and that name might not have a value in a particular instance; therefore, the variable will not return a value.

Optional<String> name;
Optional<String> getName();

void doSomething(){
assertThat("My Name").isEqualTo(getName());
}

Additionally, the Optional class has some methods that handle how we do null pointers or null checks. Same with methods, like our Optional String getName. So this time, in the above code, we create a new Optional<String> for both the variable and method getName.

By doing this, we are specifying that name may return no result so that it could be null, but because we’re using Optional, we will know that we need to handle that case.

We put together four examples to give you an idea of how to do this.

Example 1

In the first example, we cover the basics.

  1. Create an empty Optional object using the empty() method to return an empty Optional instance.
    static <T> Optional<T> empty()
  2. Check to see that Optional is empty. The isEmpty() method checks to see if a value is not present, then returns true; otherwise false.
    boolean isEmpty()
  3. Check to see that Optional is not present. The isPresent() method returns true if there is a value present; otherwise false.
    boolean isPresent()

Example 2

in the second example, we’ll look at creating an optional from an object that could be known. So we’re gonna look at converting an object to an optional. We’re going to look at some of the issues of how we could get a null pointer, and then we’re going to look at creating an optional with nullable.

  1. Create an Optional object from an object using the of() method. The of() returns an Optional describing the given non-null value.
    static <T> Optional<T> of(T value)
  2. Caution: The of() method can’t be null. If the Object is null, then it will throw a NullPointerException.
    Sting name = null;
    Optional<String> optionalName = Optional.of(null);
  3. Create an Optional with an Object that could be Null. Using the ofNullable() method will return an Optional describing the given value; if non-null, otherwise returns an empty Optional.
    static <T> Optional<T> ofNullabl(T value)

Example 3

In this example, we will dive deeper into the optional class and start looking at some of the conditional options we have with the optional class.

  1. Get the Object from the Optional using the get() method. If a value is present, return the value; otherwise, throw NoSuchElementException.
    T get()
  2. Null check vs. Optional ifPresent. If a value is present, perform the given action with the value; otherwise, do nothing.
    void ifPresent(Consumer<? super T> action)
  3. Java 9 ifPresentOrElse to override nulls with supplier functional interfaces. If a value is present, return the value; otherwise, return the other.
    T orElse(T other)
  4. Use orElse to override nulls. If a value is present, perform the given action with the value; otherwise, perform the given empty-based action.
    void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
  5. Use orElseGet to override nulls with a supplier functional interface. If a value is present, it returns the value; otherwise, it returns the result produced by the supplying function.
    T orElseGet(Supplier<? extends T> supplier)
  6. Use orElseThrow to override the exception. If a value is present, return the value; otherwise, throws NoSuchElementException.
     T orElseThrow()
  7. 7. Java 10 introduced simple orElseThrow to throw NoSuchElementException. If a value is present, it returns the value; otherwise throws an exception produced by the exception-supplying function.<
     <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)

Example 4

In our last example, we will look at using the stream() method to map() our optional objects into their object counterparts. So this could be useful for JPA Entities or just plain old objects. We can also use the filter method to remove nulls or pull out the specific data we want from within our streams.

  1. Look at using stream() & map() to convert a List<String> to List<Optional<String>>.
    • with stream() If a value is present, it returns a sequential Stream containing only that value; otherwise returns an empty Stream.
      Stream<T> stream()
    • with map() If a value is present, returns an Optional describing (as if by ofNullable(T)) the result of applying the given mapping function to the value; otherwise, returns an empty Optional.
       <U> Optional<U> map(Function<? super T,? extends U> mapper)
  2. Use filter() to remove nulls. If a value is present and matches the given predicate, it returns an Optional describing the value; otherwise, it returns an empty Optional.
    Optional<T> filter(Predicate<? super T> predicate)
  3. Expand on filter() using multiple filters to get specific values.
  4. Using flatMap(): If a value is present, returns the result of applying the given Optional-bearing mapping function to the value, otherwise, returns an empty
    Optional.<U> Optional<U> flatMap(Function<? super T,? extends Optional<? extends U>> mapper)

Finally, this series comes from our mentoring/mastermind classes.  These classes are virtual meetings that focus on how to improve our technical skills and build our businesses.  After all, the goals of each member vary.  However, this diversity makes for great discussions and a ton of educational value every time we meet.  We hope you enjoy viewing this series as much as we enjoy creating it.  As always, this may not be all new to you, but we hope it helps you be a better developer.

Other Classes, You Might Consider:

Leave a Reply