空的检查链vs捕捉NullPointerException [英] Null check chain vs catching NullPointerException

查看:199
本文介绍了空的检查链vs捕捉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 可能是缺席使得这个事实对读者来说是非常明显和清晰的,类型系统将确保你不会意外忘记它。



你还可以访问工作方法这些值更方便,如 地图


/

为什么不可选?



我不能使用可选的唯一原因可选如果这是一个真正的性能关键部分的代码,如果垃圾收集开销是一个问题。这是因为每次执行代码时都会分配几个可选对象,并且VM 可能不能优化这些对象。在这种情况下,您的原始if-tests可能会更好。


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()

The problem is that getFoo(), getBar(), getBaz() may all return 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();

Is it acceptable to write

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

or would that be considered an antipattern?

解决方案

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 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?

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.


Maybe more optionals?

If on the other hand absent values from the intermediate methods are valid, maybe you can switch to Optionals 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());        
}


Why optional?

Using Optionals 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.

You also get access to methods for working with such values more conveniently, like map and orElse.


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.

这篇关于空的检查链vs捕捉NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆