Java 你真的需要'finally'块吗

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3861522/
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-14 05:57:00  来源:igfitidea点击:

Do you really need the 'finally' block

javaexception-handling

提问by Amit Kumar Gupta

There are 3 permutations of a try...catch...finally block in java.

java 中的 try...catch...finally 块有 3 种排列。

  1. try...catch
  2. try...catch...finally
  3. try...finally
  1. 试着抓
  2. 尝试……抓住……终于
  3. 尝试...最后

Once the finally block is executed, control goes to the next line after the finally block. If I remove the finally block and move all its statements to the line after the try...catch block, would that have the same effect as having them in the finally block?

一旦 finally 块被执行,控制就会转到 finally 块之后的下一行。如果我删除 finally 块并将其所有语句移动到 try...catch 块之后的行,这是否与将它们放在 finally 块中的效果相同?

采纳答案by Sisyphus

I think willcode comes the closest to expressing the key point here, and probably everyone means it but are not clear.

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

The problem is there is indeed something very wrong with what you are asking: "If i write all the statements after catch block instead of writing them into finally block then then would there be anything wrong?"

问题是您所问的确实存在一些非常错误的问题:“如果我在 catch 块之后写入所有语句而不是将它们写入 finally 块中,那么会有什么问题吗?”

If you write all the statements after the catch block, what you are implying is that

如果你在 catch 块之后写了所有的语句,你的意思是

1) You will always catch the exception.

1)您将始终捕获异常。

2) You will always continue on to the next statements after you catch the exception.

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

This implies that you will always continue the execution "normally" after an exception, which is generally something you neverin fact want to do.

这意味着您将始终在异常之后“正常”继续执行,这通常是您实际上永远不想做的事情。

Exceptions should be just that - exceptional. If you can in fact handle an exception, it is always better to write your code to consider those conditions first and not lead to an exception at all. If you follow this model then exceptions are truly exceptional - conditions you could not anticipate or at most not fix. Really not anticipate is what you should work towards. This means in general you are unable to handle true exceptions, which also means you should not just continue execution, often you end the application instead.

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

What is normally done is you allow an error to propagate back up the call stack. Some say this is done on the off chance that someone higher up in the chain may be able to handle it. I would say that essentially never happens, there are two real purposes to do this. One it may be something the user can fix, if there is one. So you propagate the error back up until you get to where you can report it to the user. Or two, a user cannot fix it but you want to get the entire call stack for debugging. Then you catch it at the top to fail gracefully.

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

The finally block now should have more meaning to you. As everyone says it always runs. The clearest use of a finally is really in a try... finally block. What you are now saying is if the code runs fine, great. We still need to do some clean up and the finally always executes then we move on. But if an exception occurs, we now really need that finally block because we may still need to do some clean up, but we are no longer catching the exception here so we are not going to be moving on anymore. The finally block is essential to ensure that clean up occurs.

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

The idea of an exception always halting execution may be hard for someone to grasp until they have a certain amount of experience, but that is in fact the way to always do things. If an error happened, either it was so minor you should have accounted for it to begin with, or else there are just more and more errors waiting to happen down the line.

异常总是停止执行的想法可能对某人来说很难理解,直到他们有一定的经验,但这实际上是总是做事的方式。如果发生了错误,要么是因为它太小了,你应该一开始就考虑到它,要么就是有越来越多的错误等待着发生。

"Swallowing" errors - catching them and moving on is the worst thing you can do because your program becomes unpredictable and you cannot find and fix bugs.

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

Well written code will contain as many try ... finally blocks as are necessary to make sure that resources are always released no matter the outcome. But well written code generally contain only a small number of try ... catch blocks that exist primarily to allow an application to fail as gracefully as possible, or defer to the user, which means at least always pass a message to the user etc. But you usually do not just catch an error and keep going.

编写好的代码将包含尽可能多的 try ... finally 块,以确保无论结果如何,资源总是被释放。但是编写良好的代码通常只包含少量的 try ... catch 块,它们的存在主要是为了让应用程序尽可能优雅地失败,或者服从用户,这意味着至少总是向用户传递消息等。但是您通常不会只是发现错误并继续前进。

回答by Noon Silk

Yes, there would be something very critically wrong.

是的,会有一些非常严重的错误。

And that is, your code would only run if there is an error.

也就是说,您的代码只会在出现错误时运行。

Statements inside finallyalways run, regardless of an exception being thrown. That is the point.

finally无论抛出异常,内部语句始终运行。这就是我想说的。

回答by willcodejavaforfood

The highlight is that a finallyblock is guaranteed to be executed even if an exception is raised and not caught. You then use the finallyblock, as a one time chance, to perform necessary clean-up like closing streams. The code after the finally block might never be reached.

重点是finally即使引发了异常并且没有被捕获,块也能保证被执行。然后finally,您可以使用该块作为一次性机会来执行必要的清理,例如关闭流。finally 块之后的代码可能永远不会到达。

From the java tutorial

来自java教程

The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.

finally 块总是在 try 块退出时执行。这确保即使发生意外异常也能执行 finally 块。但 finally 不仅仅用于异常处理——它允许程序员避免通过 return、continue 或 break 意外绕过清理代码。将清理代码放在 finally 块中始终是一个好习惯,即使没有预料到异常也是如此。

回答by Sascha

The finally block contains lines of code that should be executed regardless whether an exception has been caught or not. Even if you decide to stop code running in that method. So code after the t-c-f might not be executed, but the finally code is "guaranteed" (guaranteed in the sense of a non crashing immediately breaking non handleable error).

finally 块包含无论是否捕获到异常都应该执行的代码行。即使您决定停止在该方法中运行的代码。因此 tcf 之后的代码可能不会被执行,但最终代码是“有保证的”(在非崩溃立即破坏不可处理错误的意义上保证)。

回答by janasainik

finally block especially used at the time of exception prevention. If any runtime error occurs, the program may lead to terminate. So at this time, it will call finally block before going to terminate the program. Usually 'finally' contains connection closing statements, save operations and file input, output close operations.

finally 块,特别是在异常预防时使用。如果发生任何运行时错误,程序可能会导致终止。所以这个时候,它会在去终止程序之前调用finally块。通常“finally”包含连接关闭语句、保存操作和文件输入、输出关闭操作。

回答by Max Lybbert

If I understand the question, you're asking what's the difference between:

如果我理解这个问题,你会问有什么区别:

try {
    Foo f = new Foo();
    f.bar();
}
finally
{
    Foo.baz();
}

And:

和:

// This doesn't actually compile because a try block needs a catch and/or finally block
try {
    Foo f = new Foo();
    f.bar();
}
Foo.baz();

Or, more likely:

或者,更有可能:

Foo f = new Foo();
f.bar();
Foo.baz();

The difference is that if either new Foo()or f.bar()throw an exception, the finallyblock will get executed in the first case, but that Foo.baz()won't get executed in the last two cases: instead control will skip over Foo.baz()while the JVM looks for an exception handler.

不同之处在于,如果new Foo()f.bar()抛出异常,finally块将在第一种情况下执行,但Foo.baz()在后两种情况下不会执行:相反Foo.baz(),在 JVM 寻找异常处理程序时,控制将跳过。



EDIT

编辑

Responding to your comment, what about:

回应你的评论,关于:

Foo f = new Foo();
try {
    f.bar();
}
catch (Exception ex)
{
    // ...
}

f.baz();

You are right that, assuming the catchblock doesn't rethrow the exception, or return from the method indicating a failure occured, then f.baz()gets called regardless of whether there was an exception. Even in that case, however, the finallyblock serves as documentation that f.baz()is used for cleanup.

你是对的,假设catch块没有重新抛出异常,或者从指示发生失败的方法返回,然后f.baz()不管是否有异常都会被调用。但是,即使在这种情况下,该finallyf.baz()也可用作用于清理的文档。

More importantly, the fact that an exception was thrown usually is important, so it's very hard to write code that continues on doing whatever it was doing without knowing that an exception was thrown. There are times that exceptions indicate silly things that you can ignore, and in that case you should swallow the exception. More often, however, you will want to signal failure, either by rethrowing the exception (or throwing a different exception) or returning from the method with an error code.

更重要的是,抛出异常这一事实通常很重要,因此很难编写代码继续执行其正在执行的任何操作而不知道抛出了异常。有时,异常表示您可以忽略的愚蠢的事情,在这种情况下,您应该吞下异常。然而,更多情况下,您希望通过重新抛出异常(或抛出不同的异常)或从带有错误代码的方法返回来发出失败信号。

For example, if f.bar()is supposed to convert a Stringto a Double, and on failure it throws a NumberFormatException, then code after the tryblock probably needs to know that the Stringwas not actually converted to a Double. And, so, in general you won't want to continue after the catchblock. Instead, you'll want to signal failure. This is known as "abort on failure" (compared to "resume on failure," which probably should be called "muddle on after failure with your fingers crossed").

例如,如果f.bar()应该将 a 转换String为 a Double,并且在失败时抛出 a NumberFormatException,则try块后面的代码可能需要知道 theString并未实际转换为 a Double。而且,因此,通常您不会想在catch块之后继续。相反,您需要发出失败信号。这被称为“失败时中止”(与“失败时恢复”相比,后者可能应该被称为“失败后双手交叉”)。

Except, in special cases you may be able to muddle on. For instance, the catchblock could set the relevant Doubleto Double.NaNwhich is designed specifically to propagate errors correctly in math expressions. Even in that case, the finallyblock serves as documentation that f.baz()is involved in some kind of cleanup.

除非,在特殊情况下,您可能会糊涂。例如,catch块可以设置相关DoubleDouble.NaN,专门设计用于在数学表达式中正确传播错误。即使在这种情况下,该finally块也可以作为f.baz()某种清理所涉及的文档。

回答by fastcodejava

If your code never throws exception, or you are consuming all exception that will be correct. That is not what always happens.

如果您的代码从不抛出异常,或者您正在消耗所有正确的异常。这并非总是发生的事情。

回答by Angelos Makrygiorgos

I know this is a very old question but I came across today and I was confused by the answers given. I mean, they are all correct but all answer on a theoretical or even philosophical level when there is a very straightforward practical answer to this question.

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

If you put a return, break, continue or any other java keyword that changes the sequential execution of code inside the catch block (or even try block), the statements inside the finally block will still be executed.

如果您在 catch 块(甚至是 try 块)中放置了 return、break、continue 或任何其他改变代码顺序执行的 java 关键字,则仍将执行 finally 块中的语句。

For example:

例如:

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

when executed this code will print:

执行此代码时将打印:

Exception Happened 
Finally

That is the most important reason for the existence of a finally block. Most answers imply it or refer to it on the sidelines but none of them is putting emphasis on it. I think because this is kind of a newbie question such a straightforward answer is very important.

这是 finally 块存在的最重要原因。大多数答案都暗示它或在场边提到它,但没有一个人强调它。我认为因为这是一个新手问题,所以直接回答非常重要。