An Optional
brings stronger typing into operations that may fail, as the other answers have covered, but that is far from the most interesting or valuable thing Optionals
bring to the table. Much more useful is the ability to delay or avoid checking for failure, and to easily compose many operations that may fail.
Consider if you had your optional
variable from your example code, then you had to perform two additional steps that each might potentially fail. If any step along the way fails, you want to return a default value instead. Using Optionals
correctly, you end up with something like this:
return optional.flatMap(x -> x.anotherOptionalStep())
.flatMap(x -> x.yetAnotherOptionalStep())
.orElse(defaultValue);
With null
I would have had to check three times for null
before proceeding, which adds a lot of complexity and maintenance headaches to the code. Optionals
have that check built in to the flatMap
and orElse
functions.
Note I didn't call isPresent
once, which you should think of as a code smell when using Optionals
. That doesn't necessarily mean you should never use isPresent
, just that you should heavily scrutinize any code that does, to see if there is a better way. Otherwise, you're right, you're only getting a marginal type safety benefit over using null
.
Also note that I'm not as worried about encapsulating this all into one function, in order to protect other parts of my code from null pointers from intermediate results. If it makes more sense to have my .orElse(defaultValue)
in another function for example, I have much fewer qualms about putting it there, and it's much easier to compose the operations between different functions as needed.
if
statements are sooooo last decade, and everyone's using monad abstractions and lambdas now.if(x.isPresent) fails_on_null(x.get)
you exit the type system and have to keep the guarantee that the code won't break "in your head" over the (admittedly short) distance between the condition and the function call. Inoptional.ifPresent(fails_on_null)
the type system makes this guarantee for you, and you don't have to worry.Optional.ifPresent
(and various other Java constructs) is that you can only modify effectively final variables and cannot throw checked exceptions. That is reason enough to often avoidifPresent
, unfortunately.