Web 服务返回一个巨大的 XML,我需要访问它的深层嵌套字段。例如:
return wsObject.getFoo().getBar().getBaz().getInt()
问题是getFoo()
、getBar()
、getBaz()
可能都返回null
.
但是,如果我在所有情况下都检查 null
,代码会变得非常冗长且难以阅读。此外,我可能会错过某些字段的检查。
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
是真正有问题的事情,因为它们几乎可以在任何地方发生。很容易从错误中得到一个,偶然发现它并继续,好像一切正常,从而隐藏一个真正的问题。 处理起来非常棘手,因此最好完全避免。(例如,考虑自动拆箱 null 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
s 而不是 null
会使这一事实对读者来说非常明显和清晰,并且类型系统将确保您不会不小心忘记了。
您还可以更方便地访问使用这些值的方法,例如 map
和 orElse
.
缺勤是有效还是错误?
但还要考虑中间方法返回 null 是否是有效结果,或者这是否是错误的标志。如果它总是一个错误,那么抛出异常可能比返回一个特殊值更好,或者让中间方法本身抛出异常。
也许还有更多的选择?
另一方面,如果中间方法中的缺失值是有效的,也许您也可以为它们切换到 Optional
s?
然后你可以像这样使用它们:
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 测试可能会更好。
关于java - 空检查链与捕获 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37960674/