The best way to use Optional in Java

Null pointer exceptions.

They have often been a headache to java developers.

Your application breaks out of nowhere and throws null pointer exceptions.

You rub your forehead then and add that null check you missed out.

Java wanted to solve this problem.

And they introduced the Optional keyword.

They described it as a “Container” that may hold a value or may not.

So if you think a method may not return a value ,send an empty Optional object instead of null.

Something like this:

public Optional<String> getMessage(){

        String message = getMessageFromDatabase();

          if(message !=null){

             return Optional.of(message);
      }else{

           return Optional.empty();
     }


}

Notice the Optional.of() method .

This takes your string and wraps it with an Optional type.

Also notice that when there is no message in database we are returning an empty Optional.

So when your client consumes the above method they will never ever receive null!

But can they always prevent null pointer exceptions?

No! It depends on how they work with the returned Optional object.

If you just use the below code to retrieve the value from the above method , you will still get NullPointerExceptions!:

public String clientMethod(){

Optional<String> message = getMessage();

       return message.get();
}

Notice that message.get() can still return null values! and so if you use the value returned from clientMethod() without null check you will get NullPointerExceptions!

And now you may be tempted to refactor your code like below:

public String clientMethod(){

Optional<String> messageOptional = getMessage();

      if(messageOptional.isPresent()){

              return messageOptional.get();
       }else{

           return "NA";

        }

}

Notice that you can check if value is present in an Optional type using isPresent() method and then get the value using get() method.

This looks like a good way to retrieve the value.

But isn’t this duplicate code?

We are again doing a check here!

Instead of null check we are doing isPresent() check here.

If a developer remembers to put in isPresent() method check , he/she can very well remember to put in the null check.

There is no point in using Optional here!

So instead of getting the message using isPresent()/get() methods , do it the way below:

public String clientMethod(){


           return getMessage().orElse("NA");
}

Six lines of code replaced with a single line!

How does this work?

The method orElse() called on the Optional value returned by getMessage() does this:

  • It checks if value is present in the Optional
    • if yes it extracts that value and returns it
    • if no it returns the value whatever you pass to it (“NA” in the above case)

No conditional check in the above code! No boiler plate code!

But what if you don’t want to return a default value but want to throw an exception if no value is present .

Then the above code can be refactored as below:

public String clientMethod(){

         return getMessage().orElseThrow();
}

A java.util.NoSuchElementException will be thrown if there is no element in the Optional.

What if you want to throw a custom exception?

In that case you can refactor the above code as below:

public String clientMethod() throws MyCustomException{

         return getMessage().orElseThrow( () -> new MyCustomException("No value present"));
}

Notice that I am supplying a lamda function to the orElseThrow() method.

It takes no input parameters and returns a new custom exception MyCustomException. You should have defined this exception in your application.

Also notice that this exception is thrown from the method using throws keyword since it is a custom exception created by you.

Alright.

Let’s go back to the orElse() method used to return a default value when no value is present in the Optional object.

Is it always good to use orElse() method?

No!

Consider this code:

public String clientMethod(){

         return getMessage().orElse(getMessageFromThirdParty().orElseThrow());
}


public Optional<String> getMessageFromThirdParty(){

      //get message from a third party API and return it here.
}

In the above code we first try to retrieve the value from database using getMessage() method . If it is not present then we get it from third party API . If it is not sent by third party API as well we throw an exception.

The code getMessageFromThirdParty().orElseThrow() is passed as a parameter to orElse() method.

In the above scenario when you use orElse() method both getMessage() and getMessageFromThirdParty() will be executed even if getMessage() returns a value!

This is because orElse() method will always be executed whether an optional is present or not.

If getMessage() returns a value there is no need to execute getMessageFromThirdParty() method. That is a performance hit!

How to solve this?

By using orElseGet() method

If we refactor the above code as below:

public String clientMethod(){

         return getMessage().orElseGet( () -> getMessageFromThirdParty().orElseThrow());
}

The orElseGet() method takes in a lamda function as parameter and it will be executed ONLY IF getMessage() returns an empty Optional!

So you gain the performance value using orElseGet().

That’s it!


Posted

in

,

by

Comments

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading