The Optional class – a very handy utility for null hunting… and more

Read Time:5 Minute, 46 Second

Having the NullPointerException exception thrown is not a pleasant thing but it’s as common as writing “hello world” app as our first program when learning programming. It happens when we try to call a method on a null.

It usually happens without our prior knowledge that the program will try to call method on null and it is caused both by our codding inaccuracy (overlooking) and little experience with such cases – the more we code the more we are able to avoid those errors. With Java 8 release we had been introduced to Optional class. It helps us to deal with that kind of errors a lot. The “null hunting”, as I call it, is not the main reason why the Optional class was designed. When it’s used it informs programmer that a null value can be passed “legally”. Optional<T> type object can return us object of type T or null – and that’s fine – it’s our design choice and a concious decision.

In order to instantiate an Optional type object we use static fabric method built into Optional class. These are:

static<T> Optional<T> empty()
static <T> Optional<T> of(T value)
static <T> Optional<T> ofNullable(T value)

First one returns an empty Optional object  – that’s quite straighforward.

The of method creates an Optional object with T type object as a value which we have passed as a parameter. For example:

package app;

import java.util.Optional;

public class OptionalApp {

    public static void main(String[] args) {

        String theText = "Some text to be put into Optional";
        String theOtherTxt = null;

        Optional.of(theText).ifPresent(System.out::println);
        Optional.of(theOtherTxt).ifPresent(System.out::println);
    }
}

Output:

Some text to be put into Optional
Exception in thread "main" java.lang.NullPointerException
  at java.util.Objects.requireNonNull(Objects.java:203)
  at java.util.Optional.<init>(Optional.java:96)
  at java.util.Optional.of(Optional.java:108)
  at app.OptionalApp.main(OptionalApp.java:13)

After I tried to pass null to of method I got the NullPointerException – that was easy to predict. After passing a non-null object it passes it to println method and prints the result on the screen.

The most compelling method is ofNullable – we can pass an object and check whether it’s empty or not. If it’s not, we can execute some code using Consumer interface (check my article on java.util.function package to find out more)!

Also we can use Optional instead of nested if statements! Let’s extend the above code:

import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class MyType {
    private String val;

    MyType() {
    }

    String getVal() {
        return val;
    }

    void setVal(String val) {
        this.val = val;
    }
}

public class OptionalApp {

    public static void main(String[] args) {

        String theText = "Some text to be put into Optional";
        MyType theOtherTxt = new MyType();

        Optional.of(theText).ifPresent(System.out::println);
        Optional.of(theOtherTxt).ifPresent(System.out::println);


        if (theOtherTxt.getVal() == null) {
            Stream.of(1, 2, 4, 5, 6, 7, "empty text that was!").collect(Collectors.toList()).forEach(System.out::println);
        }

        ///or using Optional:

        Optional.ofNullable(theOtherTxt.getVal()).ifPresent(System.out::println);
        /// we don't get any value as the getVal() method return nothing

        Optional.ofNullable(theText).ifPresent(System.out::println);
        // it prints out the text!
    }
}

Output:

Some text to be put into Optional
app.MyType@682a0b20
1
2
4
5
6
7
empty text that was!
Some text to be put into Optional

As you can see – I have used Optional as a wrapper to the object that could be returend by getVal() method – it returned null so the println wasn’t executed. The same applies to the if statement – the condition was not fullfilled (it returned false) therefore the code was not executed as well.

When I passed theText variable it printed out it’s content as it was not null! That’s how it works. It’s really handy and elegant.

Using Optional class as a wrapper object we are given access to other, non-static methods provided by the class. The Optional type objects are also returned by some methods from Java Stream API (more on that can be found on my Java Stream API articles).

Let’s have a look at other methods provided by the Optional class.

We have a stream of words and want to filter them by length and whether it has “.” or not. The findFirst() method returns us an Optional.

package app;

import java.util.Arrays;
import java.util.List;

public class OptionalAppTwo {

    public static void main(String[] args) {


        List<String> words = Arrays.asList("This", "is", "some", "sentence.", "The", "other", "one.");

        System.out.println(words.stream().filter(word -> word.length() > 3 && !word.contains(".")).findFirst());


    }
}

output:

Optional[This]

The output may seem odd at first glance, but it’s not in fact. I have put whole expression into the println() method thus it has invoked toString() on the Optional object returend by findAny().  That’s the out put of invoking toString() on the Optional, no the valiue returned by the filtered stream!

Ok, I will change the filter a little bit:

System.out.println(words.stream().filter(word -> word.length() > 10 && !word.contains(".")).findFirst());

I have changed the minimal length to 10 – there’s no such word in my list of words so findFirst() returns an empty Optional.

Output:

Optional.empty

What if I want to execute some code or return some default value in case the stream returns null? Optional class has an answer!

I assign the output of the stream to the reference and use  T orElse(T other) to return some String , T orElseGet(Supplier<? extends T> other) to pass return a value of the Supplier executed within the method, or just simply throw an exception using <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X

package app;

        import java.util.Arrays;
        import java.util.List;
        import java.util.Optional;

public class OptionalAppTwo {

    public static void main(String[] args) {


        List<String> words = Arrays.asList("This", "is", "some", "sentence.", "The", "other", "one.");

        Optional<String> optionalWord = words.stream()
                .filter(word -> word.length() > 10 && !word.contains(".")).findFirst();

        System.out.println(optionalWord.orElse("There's no word with length > 10 so I'm returning this!"));
        // orElse returns the object of the type stored in the Optional we are invoking when the object is empty
        // in this case String!

        System.out.println(optionalWord.orElseGet(OptionalAppTwo::returner));
        // orElseGet takes supplier as a parameter and returns its returned value.
        // I have used simple static method to visualize this.

    }

    static String returner(){
        return "some other words";
    }
}

Output:

There's no word with length > 10 so I'm returning this!
some other words
Exception in thread "main" java.util.NoSuchElementException
	at java.util.Optional.orElseThrow(Optional.java:290)
	at app.OptionalAppTwo.main(OptionalAppTwo.java:26)
Happy
Happy
0 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x