你真的需要“最后”的块吗?

有3个排列的try … catch … finally在java中阻塞。

  1. 试着抓
  2. 尝试…赶上…终于
  3. 尝试……终于

一旦finally块被执行,控制权就会在finally块之后的下一行。 如果我删除了finally块,并将其所有的语句移动到try … catch块之后,那么和finally块中的它们有相同的效果吗?

我认为,意志代码在这里最接近expression重点,可能每个人都意味着它,但不清楚。

问题在于你所问的确有些问题:“如果我把所有的语句写在catch块后面,而不是写入finally块,那么会出现什么错误?”

如果你在catch块之后写出所有的语句,你所暗示的就是这个

1)你总是会发现exception。

2)在你发现exception之后,你会一直继续下一个语句。

这意味着你将永远继续执行“正常”之后的exception,这通常是你永远不会想要做的事情。

例外应该就是这样 – 例外。 如果事实上可以处理exception,那么编写代码首先考虑这些条件总是更好,而不会导致exception。 如果你遵循这个模型,那么例外是非常特殊的 – 你无法预料或至多不能解决的情况。 真的不要期望是你应该努力。 这意味着一般情况下,您无法处理真正的exception,这也意味着您不应该继续执行,而是经常结束应用程序。

通常做的是你允许一个错误传播callback用堆栈。 有人说这样做是为了避免连锁高层可能能够应付的机会。 我会说基本上不会发生,有两个真正的目的来做到这一点。 一个可能是用户可以修复的东西,如果有的话。 因此,您将错误传播回去,直到您可以将其报告给用户。 或者二,用户不能修复它,但你想获得整个调用堆栈debugging。 然后你抓住它在顶部失败优雅。

现在最后的块应该对你有更多的意义。 正如大家所说,它总是运行。 终于清楚地使用终于真的在一个尝试…终于块。 你现在说的是如果代码运行良好,很好。 我们仍然需要做一些清理,最后总是执行,然后我们继续前进。 但是如果发生exception,我们现在真的需要这样做,因为我们可能还需要做一些清理工作,但是我们不再在这里捕捉exception,所以我们不会再继续前进。 finally块是确保清理发生的关键。

一个例外总是停止执行的想法可能很难被人掌握,直到他们有一定的经验,但实际上这是总是做事的方式。 如果发生了一个错误,或者它是如此轻微,那么你应该把它作为开始,否则就会有越来越多的错误等待发生。

“吞咽”错误 – 抓住他们继续前进是最糟糕的事情,你可以做,因为你的程序变得不可预知,你不能find并修复错误。

写得好的代码将包含尽可能多的try … finally块,以确保资源总是被释放,而不pipe结果如何。 但编写良好的代码通常只包含less量的try … catch块,它们主要是为了使应用程序尽可能优雅地失败,或者推迟给用户,这意味着至less总是向用户传递消息等。但是,你通常不只是发现错误而继续前进。

即使发生exception,也会保证finally块被执行。 你用它们来进行必要的清理,比如closuresstream。 finally块之后的代码可能永远无法到达。

从java 教程

finally块总是在try块退出时执行。 这确保即使发生意外的exception也能执行finally块。 但是最后对于不仅仅是exception处理而言是有用的 – 它允许程序员避免由于返回,继续或中断而意外绕过清除代码。 清理代码放在finally块里总是一个很好的习惯,即使没有预期的例外。

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

如果你把一个return,break,continue或者任何其他的java关键字改变了catch块中的代码的顺序执行,那么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 

这是存在一个最终块的最重要的原因。 大多数的答案意味着它或在场外提及它,但是没有一个是强调它的。 我觉得因为这是一个新手问题,这个直截了当的答案是非常重要的。

如果我明白这个问题,你是问有什么区别的:

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

和:

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

或者,更可能的是:

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

不同的是,如果new Foo()f.bar()抛出exception, finally块将在第一种情况下被执行,但是在最后两种情况下Foo.baz()不会被执行:当JVM查找exception处理程序时,控制将跳过Foo.baz()


编辑

回应你的评论,那么呢:

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

你是对的,假设catch块不会重新抛出exception,或者从方法返回指示失败发生,然后f.baz()被调用,无论是否有exception。 但是,即使在这种情况下, finally块也是用来清理f.baz()文档。

更重要的是,抛出exception通常是非常重要的,所以很难编写代码,继续执行所做的任何事情,而不知道抛出exception。 有时候,exception表明你可以忽略的愚蠢的东西,在这种情况下,你应该吞下exception。 然而,更常见的情况是,您要通过重新抛出exception(或抛出一个不同的exception)或从错误代码返回方法来发信号失败。

例如,如果f.bar()应该将String转换为Double ,并且在失败时抛出一个NumberFormatException ,那么在try块之后的代码可能需要知道该String实际上没有被转换为Double 。 所以,一般来说,你不会想要在catch块之后继续。 相反,你会想要失败。 这就是所谓的“失败中止”(相对于“失败时恢复”,或许应该被称为“在你的手指越过失败后混淆)”。

除了特殊情况,你可能会混淆。 例如, catch块可以将相关的Double设置为Double.NaN ,它专门用于在mathexpression式中正确传播错误。 即使在这种情况下, finally块也作为f.baz()参与某种清理的文档。

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

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

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

无论发生什么exception, finally都会运行语句。 这就是我想说的。

最后阻止在exception预防时特别使用。 如果发生任何运行时错误,程序可能会导致终止。 所以在这个时候,它会在终止程序之前调用finally块。 通常'finally'包含连接closures语句,保存操作和文件input,输出closures操作。

如果你的代码永远不会抛出exception,或者你正在消耗所有exception将是正确的。 这并不总是发生。

两个月前,我在“try / catch”中为“finally”背后的原因写了一篇文章。

意识到一个链接在这里以一种维基风格的方式进行编辑。

这是一个独立的post,只是复制它不会工作,因为你会错过后续评论,这也增加了价值。