Ami*_*pta 67 java exception-handling
在try中有3个try ... catch ... finally块的排列.
执行finally块后,控制转到finally块之后的下一行.如果我删除finally块并将其所有语句移到try ... catch块之后的行中,那么它与finally块中的它们具有相同的效果吗?
小智 68
我知道这是一个非常古老的问题,但我今天遇到了,我对给出的答案感到困惑.我的意思是,他们都是正确的,但是当对这个问题有一个非常直接的实际答案时,所有答案都在理论上甚至是哲学层面.
如果你把一个return,break,continue或任何其他java关键字改变了catch块中的代码的顺序执行(甚至是try块),那么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");
}
Run Code Online (Sandbox Code Playgroud)
执行时,此代码将打印:
Exception Happened
Finally
Run Code Online (Sandbox Code Playgroud)
这是存在最终块的最重要原因.大多数答案暗示它或在场边提及它,但没有一个是强调它.我认为因为这是一个新手问题,所以直截了当的答案非常重要.
Sis*_*hus 48
我认为willcode最接近于表达关键点,并且可能每个人都意味着它但不清楚.
问题是你问的问题确实存在一些问题:"如果我在catch块之后编写所有语句而不是将它们写入finally块,那么会出现什么问题吗?"
如果您在catch块之后编写所有语句,那么您所暗示的是
1)你将永远抓住异常.
2)在捕获异常后,您将始终继续执行下一个语句.
这意味着您将始终在异常后"正常"继续执行,这通常是您实际上从未想过的事情.
例外情况应该是 - 例外.如果您实际上可以处理异常,那么编写代码以首先考虑这些条件并且根本不会导致异常总是更好.如果你遵循这个模型,那么异常就是非常特殊的 - 你无法预料或最多无法修复的条件.真的没有预料到你应该努力的方向. 这通常意味着您无法处理真正的异常,这也意味着您不应该只是继续执行,而是经常结束应用程序.
通常做的是允许错误传播回调用堆栈.有人说这是在链中较高的人可能能够处理它的情况下完成的.我会说基本上永远不会发生,有两个真正的目的要做到这一点.一个可能是用户可以修复的东西,如果有的话.因此,您将错误传播回来,直到您可以将其报告给用户的位置.或者两个,用户无法修复它,但您希望获得整个调用堆栈以进行调试.然后你在顶部抓住它以优雅地失败.
finally块现在应该对你有更多的意义.众所周知,它总是运行.最后一个最明确的使用是真的在尝试...最后块.你现在说的是代码运行良好,很棒.我们仍然需要做一些清理,最后总是执行然后我们继续前进.但是如果发生异常,我们现在真的需要最终阻止,因为我们可能仍然需要做一些清理,但我们不再在这里捕获异常,所以我们不再继续前进了.finally块对于确保进行清理至关重要.
总是停止执行的异常的想法可能很难让人掌握,直到他们有一定的经验,但这实际上是总是做事情的方式.如果发生错误,要么它是如此轻微,你应该考虑到它开始,否则只有越来越多的错误等待发生.
"吞咽"错误 - 抓住它们并继续前进是你可以做的最糟糕的事情,因为你的程序变得不可预测,你找不到并修复错误.
编写良好的代码将包含尽可能多的try ... finally块,以确保无论结果如何都始终释放资源.但编写良好的代码通常只包含少量try ... catch块,这些块主要是为了让应用程序尽可能优雅地失败,或者推迟到用户,这意味着至少总是将消息传递给用户等.但是你通常不会抓住错误并继续前进.
Max*_*ert 10
如果我理解这个问题,你问的是什么区别:
try {
Foo f = new Foo();
f.bar();
}
finally
{
Foo.baz();
}
Run Code Online (Sandbox Code Playgroud)
和:
// 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();
Run Code Online (Sandbox Code Playgroud)
或者,更有可能:
Foo f = new Foo();
f.bar();
Foo.baz();
Run Code Online (Sandbox Code Playgroud)
区别在于,无论是new Foo()
或者f.bar()
抛出异常,finally
块都将在第一种情况下执行,但Foo.baz()
在最后两种情况下不会执行:相反,Foo.baz()
当JVM查找异常处理程序时,控制将跳过.
编辑
回应你的评论,那么:
Foo f = new Foo();
try {
f.bar();
}
catch (Exception ex)
{
// ...
}
f.baz();
Run Code Online (Sandbox Code Playgroud)
你是对的,假设catch
块没有重新抛出异常,或者从表明发生故障的方法返回,那么f.baz()
无论是否有异常都会被调用.但是,即使在这种情况下,该finally
块f.baz()
也可用作用于清理的文档.
更重要的是,抛出异常的事实通常很重要,因此编写代码继续执行它正在做的事情而不知道抛出异常是非常困难的.有时,异常表示您可以忽略的愚蠢的事情,在这种情况下,您应该吞下异常.但是,更常见的情况是,您需要通过重新抛出异常(或抛出不同的异常)或从带有错误代码的方法返回来发出失败信号.
例如,如果f.bar()
应该将a转换String
为a Double
,并且在失败时它会抛出a NumberFormatException
,然后代码try
块可能需要知道String
实际上没有转换为a Double
.因此,一般来说,您不希望在catch
阻止之后继续.相反,你会想要发出失败信号.这被称为"失败中止"(与"失败时恢复"相比,可能应该称之为"在手指交叉失败后混乱").
除此之外,在特殊情况下,您可能会混淆.例如,catch
块可以设置专门设计的相关值Double
,Double.NaN
以便在数学表达式中正确传播错误.即使在这种情况下,该finally
块也可用作f.baz()
某种清理所涉及的文档.
归档时间: |
|
查看次数: |
26346 次 |
最近记录: |