空检查链与捕获 NullPointerException [英] Null check chain vs catching NullPointerException
问题描述
Web 服务返回一个巨大的 XML,我需要访问它的深层嵌套字段.例如:
A web service returns a huge XML and I need to access deeply nested fields of it. For example:
return wsObject.getFoo().getBar().getBaz().getInt()
问题是getFoo()
、getBar()
、getBaz()
可能都返回null
.
The problem is that getFoo()
, getBar()
, getBaz()
may all return null
.
但是,如果我在所有情况下都检查 null
,代码会变得非常冗长且难以阅读.此外,我可能会错过某些字段的检查.
However, if I check for null
in all cases, the code becomes very verbose and hard to read. Moreover, I may miss the checks for some of the fields.
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;
}
或者这会被视为反模式吗?
or would that be considered an antipattern?
推荐答案
捕获 NullPointerException
是真正有问题的事情,因为它们几乎可以在任何地方发生.很容易从错误中得到一个,偶然发现它并继续,好像一切正常,从而隐藏一个真正的问题.处理起来非常棘手,因此最好完全避免.(例如,考虑自动拆箱 null Integer
.)
Catching NullPointerException
is a really problematic thing to do since they can happen almost anywhere. It's very easy to get one from a bug, catch it by accident and continue as if everything is normal, thus hiding a real problem. It's so tricky to deal with so it's best to avoid altogether. (For example, think about auto-unboxing of a null Integer
.)
我建议您使用 可选
类.当您想要处理存在或不存在的值时,这通常是最佳方法.
I suggest that you use the Optional
class instead. This is often the best approach when you want to work with values that are either present or absent.
使用它,您可以像这样编写代码:
Using that you could write your code like this:
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
会使这一事实对读者来说非常明显和清晰,并且类型系统将确保您不会不小心忘记了.
Why optional?
Using Optional
s instead of null
for values that might be absent makes that fact very visible and clear to readers, and the type system will make sure you don't accidentally forget about it.
您还可以更方便地访问使用这些值的方法,例如 map
和 orElse
.
You also get access to methods for working with such values more conveniently, like map
and orElse
.
但还要考虑中间方法返回 null 是否是有效结果,或者这是否是错误的标志.如果它总是一个错误,那么抛出异常可能比返回一个特殊值更好,或者让中间方法本身抛出异常.
But also think about if it is a valid result for the intermediate methods to return null or if that is a sign of an error. If it is always an error then it's probably better throw an exception than to return a special value, or for the intermediate methods themselves to throw an exception.
另一方面,如果中间方法中的缺失值是有效的,也许您也可以为它们切换到 Optional
s?
If on the other hand absent values from the intermediate methods are valid, maybe you can switch to Optional
s for them also?
然后你可以像这样使用它们:
Then you could use them like this:
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 测试可能会更好.
Why not optional?
The only reason I can think of for not using Optional
is if this is in a really performance critical part of the code, and if garbage collection overhead turns out to be a problem. This is because a few Optional
objects are allocated each time the code is executed, and the VM might not be able to optimize those away. In that case your original if-tests might be better.
这篇关于空检查链与捕获 NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!