java中的try/catch vs null检查

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9758457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 07:17:23  来源:igfitidea点击:

try/catch vs null check in java

java

提问by Addev

Sometimes I face I must write a piece of code like this (usually it have more nested if and more complex structure but for the example is enought)

有时我面临我必须写一段这样的代码(通常它有更多的嵌套 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();
         }
     }
  }
}

when I dont need to know what failed and if something is null do nothing, an approach could be

当我不需要知道什么失败并且如果某事为空什么都不做时,一种方法可能是

public void printIt(Object1 a){
    try{
      a.getB().getC().print();
    }catch (NullPointerException e) {
    }
}

Is there something wrong in this second form like performance or other kind of issues?

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

采纳答案by Dave Newton

The exception version (similar to chains using Groovy's safe-navigation operator ?.) makes it really easy to take the Law of Demeter (or as I call it, Demeter's Strongly-Worded Suggestion) and make it your plaything for the night.

异常版本(类似于使用 Groovy 的安全导航操作符的链?.)使得采用 Demeter 定律(或者我称之为 Demeter 的强词条建议)并使其成为您晚上的玩物变得非常容易。

Similarly, deeply-nested if-statements leads to difficult-to-read code, and underneath it all, the same "violation" exists, and the cyclomatic complexity of such methods is high.

同样,深度嵌套的if-statements 导致代码难以阅读,在这一切之下,存在同样的“违规”,并且此类方法的圈复杂度很高。

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

I'd rather see LAMs (Little Auxiliary Methods) in appropriate places that encapsulate the checks and pretty much eliminate the need for the question altogether.

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

回答by Louis Wasserman

Yes. The second version will have terrible performance.

是的。第二个版本会有糟糕的表现。

Don't use exceptions for normal control flow. Effective Java item 57: use exceptions only for exceptional situations.

不要对正常控制流使用异常。Effective Java 第 57 条:仅在异常情况下使用异常。

==UPDATE==

==更新==

Even ignoring performance issues (exceptions are faster than they once were, according to my benchmark, but not nearly as fast as a simple if check), it's really code-smelly to use exceptions for standard program flow like this. JVM bytecode has special optimizations it can do for null checks, even in ifstatements. The first code sample is vastly preferred.

即使忽略性能问题(根据我的基准测试,异常比以前更快,但不像简单的 if 检查那么快),对像这样的标准程序流使用异常确实很代码。JVM 字节码具有特殊的优化,它可以对空检查进行优化,即使在if语句中也是如此。第一个代码示例非常受欢迎。

回答by khachik

The wrongest part of the second version is that when a NPE happens inside the getB(), getC()it will be silently ignored. As already mentioned, exceptions are for exceptional cases.

第二个版本最错误的部分是,当在 内部发生 NPE 时getB()getC()它会被默默忽略。如前所述,例外是针对特殊情况的。

回答by sunside

Using exceptions is always a bad idea in terms of performance, no matter how slow the mechanism used to be and is now. Whenever an exception is thrown, the full stack will be unrolled to create the stack trace. Thus, like Lois Wasserman said, you should not rely on them for (regular) program flow but for exceptional cases.

就性能而言,使用异常总是一个坏主意,无论该机制过去和现在有多慢。每当抛出异常时,整个堆栈将展开以创建堆栈跟踪。因此,就像 Lois Wasserman 所说的,你不应该依赖它们来处理(常规)程序流,而是在特殊情况下。

The nested ifs aren't the definition of beauty, but will give you the ability to print additional information like 'B is null' etc.

嵌套的 if 不是美的定义,但可以让您打印附加信息,如“B 为空”等。

回答by Bohemian

The answer is use version A.

答案是使用版本 A。

It is generally considered "bad design" to use Exceptions for flow control. Exceptions are for the "exceptional", especially NPEs which are totally avoidable using null checks. Further, using null checks, you can tell (ie log) whichterm is null (you won't know where the null is with your version B).

使用异常进行流量控制通常被认为是“糟糕的设计”。例外是针对“异常”的,尤其是使用空检查完全可以避免的 NPE。此外,使用空检查,您可以告诉(即记录)哪个术语为空(您将不知道版本 B 的空在哪里)。

Note that performance is notan issue any more throwing exceptions (the stack trace for example is only built if you use it). It's a matter of clean code.

请注意,性能不再是抛出异常的问题(例如,堆栈跟踪仅在您使用时才构建)。这是一个干净的代码问题。

However, there are some case where using exceptions for flow control is unavoidable, for example the exceptions thrown from SimpleDateFormat.parse(), because there isn't a reasonable way to tell before making the call that your input is not parsable.

但是,在某些情况下,使用异常进行流控制是不可避免的,例如从 SimpleDateFormat.parse() 抛出的异常,因为在进行调用之前没有合理的方法来判断您的输入是不可解析的。

回答by Christian Kuetbach

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

Fail fast and fail hard. If a shoud not be null, throw an Exception. This will make your code more stable and reliable.

失败得快,失败得难。如果 a 不应该为空,则抛出异常。这将使您的代码更加稳定和可靠。

So if I would have to decide between your a) and your b), I would choose a). But if a mustn't be null there, you would hide an error-situation.

因此,如果我必须在您的 a) 和 b) 之间做出决定,我会选择 a)。但是,如果 a 不能为空,您将隐藏错误情况。

回答by Noroi

A code should never include exception handlers for unchecked exceptions. A null check should always be used for an object reference which has a chance of being null.

代码永远不应该包含未经检查的异常的异常处理程序。对于有可能为空的对象引用,应始终使用空检查。

回答by nicktalbot

Definitely (a) but you should restructure the method to avoid nesting the if statements as mentioned in a previous answer. Exceptions are not the performance hit they once were but are still muchslower than checking for null and should never be used for program flow control like this. If an object can be null you should check for it but if it is not allowed you should fail fast at the point you assign the object reference. In many circumstances you can have default implementations (empty list is a good example) to avoid nulls altogether which results in much cleaner code. Avoid nulls whenever you can.

肯定是 (a) 但您应该重构该方法以避免嵌套前面的答案中提到的 if 语句。异常不再是它们曾经的性能损失,但仍然比检查 null 慢得多,并且永远不应该像这样用于程序流控制。如果一个对象可以为空,您应该检查它,但如果不允许,您应该在分配对象引用时快速失败。在许多情况下,您可以使用默认实现(空列表就是一个很好的例子)来完全避免空值,从而使代码更清晰。尽可能避免空值。

回答by matsev

If you migrate to Java 8 you can use Optionaland Lambdas. First, you need to rewrite your classes to return Optionalof each type:

如果您迁移到 Java 8,则可以使用Optional和 Lambdas。首先,您需要重写您的类以返回Optional每种类型:

class Object1 {
    private SubObject b;

    Optional<SubObject> getB() {
        return Optional.ofNullable(b);
    }
}

class SubObject {
    private SubObject2 c;

    Optional<SubObject2> getC() {
        return Optional.ofNullable(c);
    }
}

class SubObject2 {
    @Override
    public String toString() {
        return "to be printed";
    }
}

Now, you can chain the calls without the risk of NullPointerExceptions in a concise way:

现在,您可以以简洁的方式链接调用,而不会出现 NullPointerExceptions 的风险:

a.getB()
    .flatMap(SubObject::getC)
    .ifPresent(System.out::println);

See the Oracle's article Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!for more information.

请参阅 Oracle 的文章厌倦了空指针异常?考虑使用 Java SE 8 的 Optional!想要查询更多的信息。

回答by seenimurugan

Using Java 8 optional:

使用 Java 8 可选:

Optional.ofNullable(a)
            .map(Object1::getB)
            .map(SubObject::getC)
            .ifPresent(Object2::print);