问题
The java.util.Objects class was extended with a number of new methods
Objects#requireNonNullElse
respectively
Objects#requireNonNullElseGet() in Java-9
.
Both will return the first argument if it is non-null and otherwise returns the non-null second argument or the non-null value of supplier.get()
jshell> String nullStr = null;
nullStr ==> null
jshell> Objects.requireNonNullElse(nullStr,"lorem ipsum");
$13 ==> "lorem ipsum"
jshell> Objects.requireNonNullElseGet(nullStr,() -> "lorem ipsum");
$14 ==> "lorem ipsum"
But the new functionality overlaps with already existing in the Optional
class Optional#orElse and Optional#orElseGet
jshell> Optional.ofNullable(nullStr).orElse("lorem ipsum");
$17 ==> "lorem ipsum"
jshell> Optional.ofNullable(nullStr).orElseGet(() -> "lorem ipsum");
$18 ==> "lorem ipsum"
The only difference between new methods in Objects
and corresponding Optional
methods is that second argument or value of supplier must be non-null otherwise Objects
throws NPE
:
jshell> Objects.requireNonNullElseGet(nullStr,() -> null);
| java.lang.NullPointerException thrown: supplier.get()
| at Objects.requireNonNull (Objects.java:246)
| at Objects.requireNonNullElseGet (Objects.java:321)
| at (#15:1)
jshell> Objects.requireNonNullElse(nullStr,null);
| java.lang.NullPointerException thrown: defaultObj
| at Objects.requireNonNull (Objects.java:246)
| at Objects.requireNonNullElse (Objects.java:301)
| at (#16:1)
versus Optional
jshell> Optional.ofNullable(nullStr).orElse(null);
$19 ==> null
jshell> Optional.ofNullable(nullStr).orElseGet(() -> null);
$20 ==> null
- Why haven't the JDK developers updated existing methods in Optional class?
- Why haven't they introduced a new method (which will thrown NPE if second argument is null) to Optional class?
- What should we use now Optional or Objects?
- Do new methods make Objects more preferable than Optional since they will throw NPE immediately and not later on somewhere in the code like with Optional?
If I have a legacy code, something like:
String str = null;
String result = str == null ? "other string" : str;
Which is just a simple check inside a method. And I would like to re-factor it using latest language features. Now having in mind the difference between Optional.orElse
and Objects.requireNonNullOrElse
which is preferable?
result = Optional.ofNullable(str).orElse("other string");
or
result = Objects.requireNonNullOrElse(str,"other string);
回答1:
The shortest answer to your question "which is preferable?" is the all-time developer favorite "it depends" 😜 because Objects::requireNonNullElse
and Optional
cover different use cases.
The Two Alternatives
Before answering your questions I want to give some background on the two alternatives.
Objects::requireNonNullElse
Objects::requireNonNull
makes sure that the result of the call is never null (hence the name). It is usually used to succinctly verify constructor or method arguments and allows readers to verify with a glance that the variable to which the return value is assigned can not be null.
So it would not only be weird for Objects::requireNonNullElse
to suddenly allow null
, it would also be borderline useless because:
// if requireNonNullGet would allow null as second argument,
// the following is true for all x (including null)
Objects.requireNonNullElse(x, null) == x
You might argue that it is different for requireNonNullElseGet
because that might call a function that, depending on some state, might return null
or not. That's true and I assume it was considered but the requireNonNull...
API would be really weird if one of the three cases might actually allow the final result of the call to be null
even though the name says required non null.
Optional
Optional
was designed as a return argument in cases where returning null
is very likely to cause NPEs (like for a Stream
's terminal operation, where it was first used). Although some developers prefer to use it in more cases (compare Stephen Colebourne's pragmatic approach and my strict approach) no one really proposes using it as in your demonstration:
Optional.ofNullable(nullStr).orElse(null);
Optional.ofNullable(nullStr).orElseGet(() -> null);
Optional
is a way to express in the type system that something might be missing - it is not meant as an alternative to if
-null
-checks. In that sense orElse
or orElseGet
are backdoors out of Optional
back into the world of nullable types and sometimes null
is just what you want to use if something's not there, so it makes sense for them to accept null
as an argument (or the supplier's result).
Your Questions
Now we have what we need to answer your questions:
Why haven't the JDK developers updated existing methods in Optional class?
Conceptually that would go against what Optional
should be used for. But, as others have mentioned, this would be a backwards incompatible change as calls to orElse(null)
would suddenly throw exceptions.
Why haven't they introduced a new method (which will thrown NPE if second argument is null) to Optional class?
APIs are only extended if considerable improvements of existing code can be expected. I don't see that here. In many cases orElse
gets an argument that the caller creates specifically as an alternative for empty optionals - there is rarely a need to make an extra check to verify it's not null
. If you really have to, call orElse(requireNonNull(x))
.
What should we use now Optional or Objects?
If you have a variable (be it local, an argument or a field) and you want to make sure it's not null, use Objects
. If you want to return something, which may be null consider wrapping it in Optional
. Be suspicious of code that creates an Optional
(as opposed to getting one form a call) and unwraps it at the end of the same chain.
Do new methods make Objects more preferable than Optional since they will throw NPE immediately and not later on somewhere in the code like with Optional?
As I'm sure is clear by now, they cover different use cases. But let me address "and not later on somewhere in the code like with Optional": Whatever you do, make sure to check your desired nullablity property (can be null
or not) in your code. Don't return something that you assume can not be null
but it turns out to be because you didn't check. If that happens, it's not Optional
's fault.
If I have a legacy code, something like:
String str = null; String result = str == null ? "other string" : str;
Definitely Objects.requireNonNullOrElse(str,"other string");
and consider using static imports to make it more readable.
回答2:
Why haven't the JDK developers updated existing methods in Optional class?
Because that would introduce a breaking change that would break many existing programs, and because the method should allow getting null if desired.
Why haven't they introduced a new method (which will thrown NPE if second argument is null) to Optional class?
Probably because that would make the API more convoluted and bloated for no significant advantage. You can still wrap the result with requireNonNull if you want to ensure your code doesn't return null unexpectedly.
What should we use now Optional or Objects?
If you need to extract a value out of an optional returned by a method, then use Optional's method. If you want to ensure preconditions are respected for the argument of a method that should not be null, use Object.requireXxx. The JDK designers have never advocated the use of Optional just to wrap a value and check for null. Optional is for return values.
Do new methods make Objects more preferable than Optional since they will throw NPE immediately and not later on somewhere in the code like with Optional?
See previous points: you don't use these methods to do the same thing.
回答3:
The point is: those two method signatures are clearly different:
public static <T> T requireNonNullElse(T obj, T defaultObj)
vs.
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
The javadoc for the second method reads:
Returns the first argument if it is non-null and otherwise returns the non-null value of supplier.get().
In other words: it uses the supplier that you provide to it here.
So, the answer is: you use the second version for situations where you want to work with a supplier; and otherwise you simply take the "more simple" version of that method that takes the "less complicated" parameter.
The reasoning behind that: when you decide between two options, you prefer that one that is easier/"less reader surprising" to use. In other words: why would you want to provide a supplier, when you can go without.
Regarding the usage of Optionals - keep in mind that their main goal was to be used for return types; not as method parameters (see here for further reading).
Then: updating existing methods in a class delivered "to the field" is almost always a no-go. You absolutely do not want to change the semantics of something that is already out in the open and used by your customers; assuming specific semantics.
回答4:
Q. Why haven't the JDK developers updated existing methods in Optional class?
A. Because Optional
class was designed to avoid NPE.
Q. Why haven't they introduced a new method (which will thrown NPE if second argument is null) to Optional class?
A. The same answer.
Q. What should we use now Optional or Objects?.
A. Both. Objects
for simple "not null" checkings and Optional
for chain operations like map
, flatMap
, `filter'.
Q. Do new methods make Objects more preferable than Optional since they will throw NPE immediately and not later on somewhere in the code like with Optional?
A. Depends on situation. If you already have Optional as return value of some method then it is preferable to use Optional.
回答5:
So the main point is if you like using ifs for checking for null or not. If you have a method that can take arguments that can be of null value, It would make more sense to use Objects. The only reasonable place to use Optional is to verify a call to a method that returns optional result.
Developers wanted to use more functional way of checking for null values, so the where using the construct Optional.ofNullable
for that purpose, which wasn't a good practice, because it was creating garbage.
来源:https://stackoverflow.com/questions/42482326/java-util-objects-vs-optional-which-is-preferable