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, "");
}
正如我们所知,我们可以在Java中使用xxx::yyy
而不是() -> xxx.yyy()
,但如果xxx
为null,它们将不同。
带有::
的版本将抛出NullPointerException,但() -> xxx.yyy()
在实际调用函数之前不会抛出异常。
为什么会这样?
我使用IntelliJ IDEA进行编码,如果代码可以使用::
而不是->
,那么IDE将显示警告,告诉我将其更改为使用::
(即使这会导致NullPointerException(。
如何解决此问题?
其他相关代码:
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;
}
正如您所看到的,如果xxx
为null,那么() -> xxx.yyy()
会创建一个函数,该函数在被调用时会抛出NPE,但如果该函数已创建但未被调用,则不会抛出异常。但xxx::yyy
立即抛出NPE。因此,如果您在两者之间进行选择,并且不想抛出NPE,请使用->
版本。
然而,还有另一种选择。您的objectNullFieldNull
方法写得有点混乱,因为作为第一个参数传递的对象与作为第二个参数传输的供应商没有明确的关系。(对我来说(第二个参数是使用第一个参数的函数似乎更自然,如下所示:
public static <O, R> R objectNullFieldNull(O o, Function<? super O, R> field, R orv) {
return o==null ? orv : objectNull(field.apply(o), orv);
}
你可以这样使用它:
objectNullFieldNull(manager2, Manager::getName, "")
或者像这个
objectNullFieldNull(manager2, m -> m.getName(), "")
如果CCD_ 14为空,则NPE也不会。
Manager::getName
是一个Function<Manager, String>
,它接受一个管理器(或null(作为其参数,并尝试对其调用getName()
。请参阅方法引用:对特定类型的任意对象的实例方法的引用。