Warm tip: This article is reproduced from serverfault.com, please click

其他-java lambda ::表达式有什么问题?

(其他 - what wrong with java lambda :: expression ? why ? what diff between :: and normal expression?)

发布于 2020-12-02 02:20:57
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;
}
Questioner
page xu
Viewed
11
khelwood 2020-12-02 20:24:44

如你所见,如果xxx为null,则() -> xxx.yyy()创建一个函数,该函数将在调用NPE时抛出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(), "")

如果NPEmanager2为null,NPE也不会

Manager::getName是一个Function<Manager, String>接受管理器(或null)作为其参数,并尝试对其进行调用的getName()请参见方法参考对特定类型的任意对象的实例方法的引用