Web服务返回巨大的XML,我需要访问它的深层嵌套字段。例如:

return wsObject.getFoo().getBar().getBaz().getInt()

问题是getFoo()getBar()getBaz()可能都返回null

但是,如果我在所有情况下都检查null,该代码将变得非常冗长且难以阅读。此外,我可能会错过某些 Realm 的检查。
if (wsObject.getFoo() == null) return -1;
if (wsObject.getFoo().getBar() == null) return -1;
// maybe also do something with wsObject.getFoo().getBar()
if (wsObject.getFoo().getBar().getBaz() == null) return -1;
return wsObject.getFoo().getBar().getBaz().getInt();

可以写吗
try {
    return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
    return -1;
}

或将其视为反模式?

最佳答案

捕获NullPointerException是的一个非常有问题的事情,因为几乎可以在任何地方发生。从错误中获取一个错误,意外地捕获它,然后像一切正常一样继续进行非常容易,从而隐藏了一个真正的问题。 处理起来非常棘手,因此最好完全避免。 (例如,考虑将空Integer自动拆箱)。

我建议您改用 Optional 类。当您要使用存在或不存在的值时,这通常是最好的方法。

使用它,您可以这样编写代码:

public Optional<Integer> m(Ws wsObject) {
    return Optional.ofNullable(wsObject.getFoo()) // Here you get Optional.empty() if the Foo is null
        .map(f -> f.getBar()) // Here you transform the optional or get empty if the Bar is null
        .map(b -> b.getBaz())
        .map(b -> b.getInt());
        // Add this if you want to return null instead of an empty optional if any is null
        // .orElse(null);
        // Or this if you want to throw an exception instead
        // .orElseThrow(SomeApplicationException::new);
}

为什么可选?

对于可能不存在的值,使用Optional而不是null可以使该事实对读者非常明显和清楚,并且类型系统将确保您不会意外忘记它。

您还可以更方便地访问使用这些值的方法,例如 map orElse

缺席有效还是错误?

但是还要考虑中间方法返回null是否是有效结果,或者这是错误的征兆。如果始终是错误,则抛出异常可能比返回特殊值更好,或者对于中间方法本身抛出异常,则抛出异常更好。

也许还有更多可选件?

另一方面,如果中间方法中缺少的值仍然有效,也许您也可以为它们切换到Optional

然后,您可以像这样使用它们:
public Optional<Integer> mo(Ws wsObject) {
    return wsObject.getFoo()
        .flatMap(f -> f.getBar())
        .flatMap(b -> b.getBaz())
        .flatMap(b -> b.getInt());
}

为什么不是可选的?

我不使用Optional的唯一原因是,这是否在代码的性能至关重要的部分,以及垃圾回收的开销是否确实是一个问题。这是因为每次执行代码时都会分配一些Optional对象,并且VM可能无法对其进行优化。在这种情况下,原始的if-tests可能会更好。

10-02 06:54
查看更多