你真的需要“最后”的块吗?
有3个排列的try … catch … finally在java中阻塞。
- 试着抓
- 尝试…赶上…终于
- 尝试……终于
一旦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,只是复制它不会工作,因为你会错过后续评论,这也增加了价值。
- 获取java.lang.VerifyError的原因
- 在ruby中捕获Ctrl-C
- 处理“java.lang.OutOfMemoryError:PermGen空间”错误
- JavaScript中的自定义例外
- 在Java中,什么时候应该创build一个检查的exception,什么时候应该是一个运行时exception?
- 处理来自Java ExecutorService任务的exception
- 什么时候应该使用Throwable而不是新的Exception?
- Windows / C ++:是否有可能findexception被抛出的代码行有“Exception Offset”
- 为什么析构函数不被exception调用?