空的检查链vs捕捉NullPointerException [英] Null check chain vs catching NullPointerException
问题描述
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;
//也可以用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;
}
还是被视为反模式?
Catching NullPointerException
是一个真正有问题的事情,因为它们会发生几乎任何地方从错误中获取一个,很容易就意外地抓住它,并且像一切正常一样继续下去,从而隐藏了一个真正的问题。 (例如,考虑一个null Integer
的自动解包。) p>
我建议您使用 可选
类。当您想使用现在或不存在的值时,这通常是最好的方法。
使用它可以编写如下代码:
public可选<整数> m(Ws wsObject){
return Optional.ofNullable(wsObject.getFoo())//如果Foo为空,那么您可以获得Optional.empty()
.map(f - > f.getBar ())//在这里,如果Bar为空,则转换为可选项或为空。
.map(b - > b.getBaz())
.map(b - > b.getInt ));
//如果要返回-1 int而不是空的可选(如果有的话)为null
// .orElse(-1);
//或者如果你想抛出一个异常,而不是
// .orElseThrow(SomeApplicationException :: new);
}
缺少有效或错误?
还要考虑一下中间方法返回null的有效结果,或者是否是错误的标志。如果它总是一个错误,那么可能会比返回一个特殊值更好地抛出异常,或者中间方法本身抛出异常。
可能更多可选项?
如果另一方面中间方法的缺失值有效,也可以切换到也可以选择
?
然后你可以这样使用它们:
public可选<整数> mo(Ws wsObject){
return wsObject.getFoo()
.flatMap(f - > f.getBar())
.flatMap(b - > b.getBaz())
.flatMap(b - > b.getInt());
}
为什么选择? h2>
使用可选
而不是 null
可能是缺席使得这个事实对读者来说是非常明显和清晰的,类型系统将确保你不会意外忘记它。
你还可以访问工作方法这些值更方便,如 我不能使用 A web service returns a huge XML and I need to access deeply nested fields of it. For example: The problem is that However, if I check for Is it acceptable to write or would that be considered an antipattern? Catching I suggest that you use the Using that you could write your code like this:
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. If on the other hand absent values from the intermediate methods are valid, maybe you can switch to Then you could use them like this:
Using You also get access to methods for working with such values more conveniently, like The only reason I can think of for not using 这篇关于空的检查链vs捕捉NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!地图
和
/
为什么不可选?
可选的唯一原因可选
如果这是一个真正的性能关键部分的代码,如果垃圾收集开销是一个问题。这是因为每次执行代码时都会分配几个可选
对象,并且VM 可能不能优化这些对象。在这种情况下,您的原始if-tests可能会更好。return wsObject.getFoo().getBar().getBaz().getInt()
getFoo()
, getBar()
, getBaz()
may all return null
.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;
}
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
.)Optional
class instead. This is often the best approach when you want to work with values that are either present or absent.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 an -1 int instead of an empty optional if any is null
// .orElse(-1);
// Or this if you want to throw an exception instead
// .orElseThrow(SomeApplicationException::new);
}
Is absence valid or error?
Maybe more optionals?
Optional
s for them also? public Optional<Integer> mo(Ws wsObject) {
return wsObject.getFoo()
.flatMap(f -> f.getBar())
.flatMap(b -> b.getBaz())
.flatMap(b -> b.getInt());
}
Why optional?
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
and orElse
.
Why not optional?
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.