When I read java docs about Objects class, I got confused about object creation. It says
Unlike the method requireNonNull(Object, String), this method allows creation of the message to be deferred until after the null check is made
Here is the method body
public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
if (obj == null)
throw new NullPointerException(messageSupplier == null ?
null : messageSupplier.get());
return obj;
}
If messageSupplier is null, will object get created?
What about this code
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) {
return (obj != null) ? obj
: requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
}
If obj is not null, will object creation happen?
CodePudding user response:
Those two methods use a similar technique for slightly different reasons.
First of all: a Supplier<SomeType>
can be provided instead of a SomeType
if it's unknown if the value will actually be required when the method is called. This can delay creation of the SomeType
object until it's actually used, avoiding the time/memory cost of the creation when it's unnecessary.
Imagine for example a line like this:
requireNonNull(someParameter, "someParameter was not given for " someOtherParameter);
If this line is executed the error message string (the second parameter) will always be constructed, no matter if someParameter
is null
or not. This is wasteful, we'd rather postpone creating the error message until it's actually needed. But writing if (someParameter == null)
before this each time defeats the purpose of the method (since that's basically all it does), so we try to find a different way.
What if instead of providing an error message, we provide something that can produce the error message if and when it's really needed. That something is a Supplier<String>
. One simple way to implement such a provider is with a lambda:
requireNonNull(someParameter, () -> "someParameter was not given for " someOtherParameter);
Now the actual creation of the error string is only executed when someParameter
is actually null
.
Often this kind of optimization is minor, but in some cases (for example inside of a frequently called method) this kind of optimization can have real tangible benefits.
requireNonNullElseGet
uses the same technique, but instead of a supplier for an error message it takes a supplier of an alternate value:
MyAwesomeObject foo = getSomeAwesomeObject(); MyAwesomeObject fooOrDefault = requireNonNullElseGet(foo, AwesomeObjectFactory::expensiveCreationMethod);
Here we use a method reference to point tell requireNonNullElseGet
how to acquire a MyAwesomeObject
if (and only if) foo
is null.
If instead we did the (probably more readable)
MyAwesomeObject fooOrDefault = requireNonNullElse(foo, AwesomeObjectFactory.expensiveCreationMethod());
then expensiveCreationMethod
would always be executed, no matter if the result is actually needed or not.
CodePudding user response:
You read a bit too much in the javadoc.
This form of requireNonNull
does not need a possible costly message String, i.e. composed of expression on variables. Instead a message supplier is passed, which might compose that String expression.
// requireNonNull(Object, String)
// Costly whether x is null or not: message used or not.
Objects.requireNonNull(x, "Error in " map.get("x") ", " user.fullName());
// requireNonNull(Object, Supplier<String>)
// Only when x is null, a message is evaluated.
Objects.requireNonNull(x, () -> "Error in " map.get("x") ", " user.fullName());
The documentation wants to express that the message will only be created when needed - with a messageSupplier.
The code looks a bit more complex, as passing null
for messageSupplier is allowed.