the_tech_maddy
the_tech_maddy

Reputation: 597

Using Optional.empty() inside catch

I have an existing method in which, I have thrown RuntimeException by catching the IOException. Now as per my requirement, I'm going to change the definition as something like below.

try {
    // error/null producing code
    Optional.of(myModel);
}catch(IOException ex) {
    // here I removed throw new RuntimeException(ex);
    Optional.empty();
}

Is this a good practice or should I keep the existing method as it is?

Upvotes: 1

Views: 1011

Answers (1)

walen
walen

Reputation: 7273

Before Optional, if you invoked the MyModel getMyModel() method, you could get only two values:

  • a MyModel instance, meaning everything went OK and a value was found; or
  • null, meaning either:
    • that everything went OK but there was no value to return; or
    • that something went wrong and the method could not return a value.

Of course, for the third scenario you could always throw an exception instead of returning null, but sometimes that's not what you want.

Optional was introduced in part to better differentiate these scenarios. So now, instead of returning MyModel, you would declare the method as Optional<MyModel> getMyModel(), which meant you could return (warning: bad programming ahead):

  • an Optional.of(myModel) instance, meaning everything went OK and a value was found; or
  • the Optional.empty() instance, meaning that everything went OK but there was no value to return; or
  • null, meaning something went wrong and the method could not return a value.

However, being that the main purpose of Optional was to avoid NPEs caused by methods returning null, it was soon found that returning null from a method declared as returning Optional was Bad Code™, so now the convention is to return Optional.empty() in the same two cases where you returned null before.

So yes, returning Optional.empty() in the event of a caught exception is one of the expected uses of Optional.
You still cannot differentiate between "no value" and "error", but at least you force the caller to take into account the possible absence of a value, and reason about what they want to do in that case: avoid any action with ifPresent(), take a default value with orElseGet(), throw an exception with orElseThrow, etc.

Source: Effective Java (3rd ed.), "Item 55: Return optionals judiciously".

Upvotes: 3

Related Questions