你真的需要“终于”块吗?

2022-08-31 12:10:54

有3个尝试的排列...抓住。。。最后在java中阻止。

  1. 尝试。。。抓住
  2. 尝试。。。抓住。。。最后
  3. 尝试。。。最后

执行最终块后,控件将转到最终块之后的下一行。如果我删除 finally 块,并在尝试后将其所有语句移动到该行...捕获块,这会与将它们放在最后的块中具有相同的效果吗?


答案 1

我知道这是一个非常古老的问题,但我今天遇到了,我对给出的答案感到困惑。我的意思是,它们都是正确的,但是当这个问题有一个非常直接的实际答案时,它们都是在理论甚至哲学层面上的答案。

如果在 catch 块(甚至尝试使用块)内放置一个 return、break、continue 或任何其他更改代码顺序执行的 java 关键字,则 finally 块内的语句仍将被执行。

例如:

public void myFunc() {

    double p = 1.0D;
    String str = "bla";
    try{
        p = Double.valueOf(str);
    }
    catch(Exception ex){
        System.out.println("Exception Happened");
        return;  //return statement here!!!
    }finally{
        System.out.println("Finally");
    }
    System.out.println("After finally");
}

执行时,此代码将打印:

Exception Happened 
Finally

这是最终阻止存在的最重要原因。大多数答案都暗示了它,或者在一旁提到它,但没有一个强调它。我认为因为这是一个新手问题,所以这样一个直截了当的答案非常重要。


答案 2

我认为willcode最接近于表达这里的关键点,可能每个人都是认真的,但不清楚。

问题是,你问的确实有一些非常错误的地方:“如果我在catch block之后写下所有语句,而不是将它们写进最终的block中,那么会有什么问题吗?

如果你在 catch 块之后写下所有语句,你所暗示的是

1)您将始终捕获异常。

2)在捕获异常后,您将始终继续执行下一个语句。

这意味着在发生异常后,您将始终“正常”继续执行,这通常是您实际上从未想过要执行的操作。

例外应该就是这样 - 例外。如果您实际上可以处理异常,那么最好先编写代码以考虑这些条件,并且根本不会导致异常。如果您遵循此模型,那么异常确实是例外 - 您无法预料或最多无法修复的情况。真正没有预料到的是你应该努力的方向。这意味着通常您无法处理真正的异常,这也意味着您不应该只是继续执行,通常您结束应用程序。

通常的做法是允许错误向上游传播调用堆栈。有人说,这样做的机会是,链条中更高层次的人可能能够处理它。我想说的是,基本上永远不会发生,这样做有两个真正的目的。一个可能是用户可以修复的东西,如果有的话。因此,您将错误传播回去,直到到达可以向用户报告错误的位置。或者两个,用户无法修复它,但您希望获取整个调用堆栈以进行调试。然后你抓住它的顶部优雅地失败。

现在最后的块对你来说应该更有意义。正如大家所说,它总是在运行。最清楚的用法终于是真的在尝试中...最后阻止。你现在说的是,如果代码运行良好,那就太好了。我们仍然需要做一些清理,最后总是执行,然后我们继续前进。但是,如果发生异常,我们现在真的需要最终的块,因为我们可能仍然需要做一些清理,但是我们不再在这里捕获异常,所以我们不会再继续前进了。最后块对于确保进行清理至关重要。

在某人拥有一定经验之前,异常总是停止执行的想法可能很难理解,但这实际上是总是做事的方式。如果发生错误,要么它是如此之小,你应该从一开始就考虑到它,要么就是有越来越多的错误等待发生。

“吞下”错误 - 捕获它们并继续前进是你能做的最糟糕的事情,因为你的程序变得不可预测,你无法找到和修复错误。

写得好的代码将包含尽可能多的尝试...最后,块是必要的,以确保无论结果如何,资源始终被释放。但是写得好的代码通常只包含少量的尝试...catch 块的存在主要是为了允许应用程序尽可能优雅地失败,或者服从用户,这意味着至少始终向用户传递消息等。但是您通常不会只是抓住错误并继续前进。


推荐