I've read here why Optional.of()
should be used over Optional.ofNullable()
, but the answer didn't satisfy me at all, so I ask slightly different:
If you are SURE that your method does not return null
, why should you use Optional
at all? As far as I know, the more or less only purpose of it is to remind the "user of a method", that he might have to deal with null
-values. If he does not have to deal with null
-values, why should he be bothered with an Optional
?
I ask, because I recently made my service-layer return Optionals instead of nulls (in certain situations). I used Optional.of()
and was highly confused when it threw a NullPointer.
A sample of what I did:
Optional valueFromDB = getUserById("12");
User user = valueFromDB.get();
.....
public Optional<User> getUserById(String id) {
//...
return Optional.of(userRepository.findOne(id)); // NullPointerException!
}
If null is not possible, I don't see why one would wrap it in an Optional
. The dude in the linked answer said "well, if a NullPointer happens, it happens right away!" But do I really want that? If the sole purpose of an Optional
is, to remind the programmer who gets such an object, to keep null
in mind (he HAS to unwrap it), why should I want to have NullPointerException
at wrapping-time?
Edit: I needed to edit the question, because it got marked as duplicate, even though I already linked said question from the start. I also did explain, why the answer did not satisfy me, but now I need to edit my text with an explanation. But here is some appendix to what I want to ask, since I got 5 answers and everyone answers a different case, but none fully covered what I try to ask here:
Is there a reason, that Optional.of(null) is impossible and they specifically added Optional.ofNullable() for the null case?
Using streams should not be the problem with my idea of the implementation.
I got a lot of insight from your answers, thanks for that. But the real question has not been answered until now, as far as I can tell/read/understand.
Maybe I should have asked: "What if we remove the Optional.of()
method and only allow Optional.ofNullable()
in Java 9, would there be any problem except backwards-compatibility?"
The other reason to use
Optional.of(value)
when you know thatvalue
can't be null is that if you want to do additional filtering operations on thatOptional
.For example:
Optional is one of those things that has been imported from functional programming languages and dumped into the laps of OO and procedural programmers without much background explanation...which has caused much pain and hand wringing.
First, a quick link to a blog post (not by me) which greatly helps to clear the air on this: The Design of Optional
Optional is related to functional programming types like Haskell Maybe. Because of the way strong typing works in functional programming, a programmer in that language would use Maybe to say that a value can be either Something, or Nothing. The Something and Nothing are actually different types, here. Anything that needs the values inside a Maybe has to handle both - the code simply won't compile if it doesn't handle both.
Compare that scenario to what is the typical situation in C-based object-oriented languages (Java, C#, C++, etc.) where an object can either have a value, or be null. If a method needs to handle null parameters as an edge case, you need to explicitly write that code - and being the lazy programmers we all are, it's just as often we don't bother to.
Imagine what coding would be like if code wouldn't compile unless null cases were always explicitly handled. That's a pretty close comparison to what happens when using Maybe in functional languages.
When we pull language features over from functional programming, and the compiler behaves the way it always has, and we code the way we always have... you can see there's a disconnect happening.
Separately, Optional can be used as a simple stand-in for null. Because it seems familiar that way, and is new, magpie developers are prone to using it as a replacement for situations where null-checks would have happened before. But, in the end, is foo.isPresent() really so different than foo != null. If that is the sole difference, it's pointless.
And let's not even get started on how Optional can be a stand-in for autoboxing and unboxing in Java.
Now, getting back to your specific question about the particular API of Optional in Java, comparing ofNullable() vs. of(), the best I can work out is that you probably aren't expected to use those in typical code. They are mainly used at the terminal end of stream() operations. You can look at the code to Optional.of() vs. Optional.ofNullable() and see for yourself that the only difference is that ofNullable checks if the value is null and arranges things for that situation.
My jaded eye doesn't see a whole lot of benefit to using Optional in Java, unless I am using Java 8 streams and I have to. Some would say that the main benefit of using Optional as a type for non-stream usage is to specify that a particular parameter is optional - that is, the logic takes a different route if it's there vs. not there. Which, again, you can simply do with null. But I would say that the mental baggage associated with Optional means that for every forward step of supposedly more verbose code, you are taking multiple steps backwards with requiring people to understand that the Optional (in this specific case) is almost entirely cosmetic. For the situation you described, I would probably go back to using nulls and null checks.
I think you are right with your opinion that you should not use Optional if you are sure that you always have a return-value.
But your method is not sure, that it always returns a value!
Think of an call to getUserById(-1). There is (normally) no User with this id, and your userRepository will return null.
So in this case you should use Optional.ofNullable.
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ofNullable-T-
The practical answer is: on most occasions, no. As you mention, if the whole point of using Optional is not knowing if a value can return null, and you want to make it explicit in certain API, the fact that .of() can throw a null exception does not make any sense. I always use ofNullable.
The only situation I can think of is if you have a method that returns Optional (to make explicit this null-value possibility), and that method has a default/fallback value under some circumstances, you will return a "default value" Optional, using .of().
Then again, someone can question whether in that case you can return this default value in case of a null.
Metaphysical discussions aside, IMHO if you use Optionals, and want them to make any sense and not throw exceptions, use ofNullable().
Yes, of course there will be compatibility issues. There's just too much code out there using
Optional.of
.I agree with your general sentiment though:
Optional.of
is doing too much (wrapping the value and null-checking). For null-checks we already haveObjects.requireNonNull
which is conveniently overloaded to accept a descriptive text.Optional.of
andOptional.ofNullable
should have been discarded in favor of a constructor made available for users:For null-checks this would have sufficed:
You are mixing up the API design rationale with knowledge within a particular implementation code. It’s perfectly possible that a method declares to return an
Optional
, because the value might be absent, while at a certain code location within the method, it is known to be definitely present. I.e.This method’s return type denotes a
String
that might be absent, while at the code locations creating anOptional
instance, it is known whether the value is present or absent. It’s not about detecting anull
value here.Likewise, within the Stream API methods
findFirst()
andfindAny()
, it will be known at one point, whether there is a matching element, whereas supporting the conversion of its presence to absence in case of a matchingnull
element is explicitly unsupported and supposed to raise aNullPointerException
, per specification. Therefore,Optional.of
will be used to return the matching element, which you can easily recognize in the stack trace when usingStream.of((Object)null) .findAny();