在java中尝试/ catch vs null检查

Add*_*dev 32 java

有时我面对我必须写一段这样的代码(通常它有更多的嵌套if和更复杂的结构,但是对于这个例子来说)

public void printIt(Object1 a){
  if (a!=null){
     SubObject b= a.getB();
     if (b!=null){
         SubObject2 c=b.getC();
         if(c!=null){
             c.print();
         }
     }
  }
}
Run Code Online (Sandbox Code Playgroud)

当我不需要知道什么是失败的,如果什么是空的什么都不做,一种方法可能是

public void printIt(Object1 a){
    try{
      a.getB().getC().print();
    }catch (NullPointerException e) {
    }
}
Run Code Online (Sandbox Code Playgroud)

第二种形式如性能或其他类型的问题是否有问题?

谢谢

Dav*_*ton 22

异常版本(类似于使用Groovy安全导航操作符的链?.)使得很容易采用Demeter法则(或者我称之为Demeter的强烈建议)并使其成为夜晚的玩物.

类似地,深度嵌套的if语句导致难以阅读的代码,并且在其下面,存在相同的"违规",并且这种方法的圈复杂度很高.

public void printIt(Object1 a) {
    if (null == a) {
        return;
    }

    SubObject b = a.getB();
    if (null == b) {
        return;
    }

    SubObject2 c = b.getC();
    if (null == c) {
        return;
    }

    c.print();
}
Run Code Online (Sandbox Code Playgroud)

我宁愿在适当的地方看到LAM(小辅助方法)来封装检查,并且几乎完全消除了对问题的需求.


Lou*_*man 11

是.第二个版本将有糟糕的表现.

不要将异常用于正常控制流程.有效的Java项目57:仅在特殊情况下使用异常.

== ==更新

甚至忽略了性能问题(根据我的基准测试,异常比以前更快,但不像简单的if检查那么快),对于像这样的标准程序流使用异常真的是代码异常.JVM字节码具有特殊的优化功能,即使在if语句中也可以进行空检查.第一个代码示例是非常优选的.

  • 这根本不是真的.Java中的异常不会导致他们过去的性能损失. (7认同)
  • @MДΓΓБДLL,他们的性能可能在较新的JVM版本中有所增加,但我仍然认为它远不及标准的空检查.制作堆栈跟踪的快照本身是一项非常昂贵的操作. (4认同)
  • 此外,"不会影响他们过去所做的性能"并不意味着他们并不慢. (2认同)

kha*_*hik 8

第二个版本的最大部分是当NPE发生在内部时getB(),getC()它将被默默地忽略.如前所述,例外情况适用于特殊情况.


Chr*_*ach 8

public void printIt(Object1 a){
    if(a==null){
        throw new IllegalArgumentException("a was null, but this is not allowed here."),
    }
    [...]
Run Code Online (Sandbox Code Playgroud)

快速失败并努力失败.如果shoud不为null,则抛出异常.这将使您的代码更稳定可靠.

所以,如果我必须在你的a)和你的b)之间做出决定,我会选择a).但是如果a不能为空,那么你会隐藏错误情况.