public static void main(String[] args) {
Manager manager1 = new Manager();
Manager manager2 = null;
// both line 1 and line 2 are ok
NullUtils.objectNullFieldNull(manager1, () -> manager1.getName(), "");
NullUtils.objectNullFieldNull(manager1, manager1::getName, "");
// line 1 is ok but line 2 will throw NullPointerException
NullUtils.objectNullFieldNull(manager2, () -> manager2.getName(), "");
NullUtils.objectNullFieldNull(manager2, manager2::getName, "");
}
As we know, we can use xxx::yyy
instead of () -> xxx.yyy()
in Java, but if xxx
is null, they will be different.
The version with ::
will throw a NullPointerException, but () -> xxx.yyy()
not throw an exception until the function is actually called.
Why is this?
I use IntelliJ IDEA to code, and if the code can use ::
instead of ->
, then the IDE will show a warning, telling me to change it to use ::
(even though that would cause a NullPointerException).
How do I resolve this?
Other related code:
public class NullUtils {
public static <O, R> R objectNullFieldNull(O o, Supplier<R> supplier, R orv) {
return Objects.isNull(o) ? orv : objectNull(supplier.get(), orv);
}
public static <O> O objectNull(O original, O target) {
return Objects.isNull(original) ? target : original;
}
}
@Data
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class Manager {
private String code;
private String name;
private String mobile;
}
As you have seen, if xxx
is null, then () -> xxx.yyy()
creates a function that will throw an NPE if it is called, but does not throw an exception if the function is created and not called. But xxx::yyy
throws an NPE immediately. So if you are choosing between the two and don't want to throw an NPE, use the ->
version.
However, there's another option. Your objectNullFieldNull
method is somewhat confusingly written, because the object passed as the first argument has no clear relationship with the supplier passed as the second argument. It would seem more natural (to me) for the second argument to be a function using the first, like this:
public static <O, R> R objectNullFieldNull(O o, Function<? super O, R> field, R orv) {
return o==null ? orv : objectNull(field.apply(o), orv);
}
You can make use of it like this:
objectNullFieldNull(manager2, Manager::getName, "")
or like this
objectNullFieldNull(manager2, m -> m.getName(), "")
and neither will NPE if manager2
is null.
Manager::getName
is a Function<Manager, String>
that accepts a manager (or null) as its argument, and attempts to call getName()
on it. See method references: Reference to an instance method of an arbitrary object of a particular type.
thx~ u have solve my problem
i add another static function u suggest to me~ i have another question:
Manager::getName
can use asFunction<? super O, R> field
why ? does it because Class's method truth first argument isthis
? i never use Class::ClassMethod,how the argument matched?could u please give some reference link or statistic that i can study by myself,or give me some key word that i can search online,thx~
docs.oracle.com/javase/tutorial/java/javaOO/…
thanks very much @khelwood