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:
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.
The other reason to use Optional.of(value)
when you know that value
can't be null is that if you want to do additional filtering operations on that Optional
.
For example:
public static long getPageSizeFrom(HttpServletRequest request) {
return Optional.of(request.getParameter("pageSize"))
.filter(StringUtils::isNumeric)
.map(Long::valueOf)
.filter(page::hasPageSize)
.orElse(page::getDefaultPageSize)
}
"What if we remove the Optional.of() method and only allow Optional.ofNullable() in Java 9, would there be any problem except backwards-compatibility?"
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 have Objects.requireNonNull
which is conveniently overloaded to accept a descriptive text.
Optional.of
and Optional.ofNullable
should have been discarded in favor of a constructor made available for users:
return new Optional<>(value);
For null-checks this would have sufficed:
return new Optional<>(Objects.requireNonNull(value, "cannot be null!"));
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.
String content;
public Optional<String> firstMatch(String pattern) {
Matcher m = Pattern.compile(pattern).matcher(content);
return m.find()? Optional.of(m.group()): Optional.empty();
}
This method’s return type denotes a String
that might be absent, while at the code locations creating an Optional
instance, it is known whether the value is present or absent. It’s not about detecting a null
value here.
Likewise, within the Stream API methods findFirst()
and findAny()
, 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 matching null
element is explicitly unsupported and supposed to raise a NullPointerException
, per specification. Therefore, Optional.of
will be used to return the matching element, which you can easily recognize in the stack trace when using Stream.of((Object)null) .findAny();
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().
public Optional<String> getSomeNullableValue() {
if (defaultSituationApplies()) { return Optional.of("default value"); }
else {
String value = tryToGetValueFromNetworkOrNull();
return Optional.ofNullable(value);
}
}
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().