Is there a real reason to use Optional.of()?

2019-02-17 03:03发布

问题:

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?"

回答1:

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();



回答2:

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)
}


回答3:

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-



回答4:

Angelika Langer says that Optional.ofNullable is only a convenience-method, calling the other both static methods from Optional. It is implemented as:

return value == null ? empty() : of(value) ;

Also she says that Optional.ofNullable was added lately to the API.

Here is her text in german language: http://www.angelikalanger.com/Articles/EffectiveJava/80.Java8.Optional-Result/80.Java8.Optional-Result.html

So I would use Optional.of only when null is an error, which should be found early. This is what Tagir Valeev said in: Why use Optional.of over Optional.ofNullable?



回答5:

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.



回答6:

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().



回答7:

"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!"));


回答8:

Optional.of() should be used when you are sure that Optional will never have a null object and it will contain the object value or it will be empty but it will not be null. Optional.of() can throw a NullPointerEception if the Optional is created with null value. Optional.ofNullable()- is a used when there are chances that the object might be null.

Optional.of() will return the object of Optional without null check. Lets look at the interns of Optional.of() method:

public static <T> Optional<T> of(T value) {
     return new Optional<>(value);
}

Optional.ofNullable() will return the object of Optional with a null check. If this method gets the null as an input then it will return the empty Optional otherwise it returns an Optional with the specified present non-null value Let's look at the interns of Optional.ofNullable() method:

public static <T> Optional<T> ofNullable(T value) {
     return value == null ? empty() : of(value);
}

You can read more about on below post : http://onlyfullstack.blogspot.com/2018/12/optional-in-java-8.html