Home > Back-end >  If line doesn't executed still object creation happens
If line doesn't executed still object creation happens

Time:07-21

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.

  •  Tags:  
  • java
  • Related