考虑以下测试用例:
public class Main {
static int a = 0;
public static void main(String[] args) {
try {
test();
System.out.println("---");
test2();
}
catch(Exception e) {
System.out.println(a + ": outer catch");
a++;
}
}
public static void test()
{
try {
throw new Exception();
}
catch (Exception e) {
System.out.println(a + ": inner catch");
a++;
}
finally {
System.out.println(a + ": finally");
a++;
}
}
public static void test2() throws Exception
{
try {
throw new Exception();
}
finally {
System.out.println(a + ": finally");
a++;
}
}
}
输出:
0: inner catch
1: finally
---
2: finally
3: outer catch
为什么test()
捕获事件发生在最后test2()
之前是什么原因解释了?
答案 0 :(得分:16)
由于try
中的test2()
块没有catch
块,因此只有finally
。代码不会“跳回”调用者进入catch
,然后“跳到”finally
继续前进,就像你想象的那样。
答案 1 :(得分:16)
关键点是:
try-(catch)-finally
块中,该特定finally
块的try
最后执行try
块,并且每个嵌套的try
块都可以拥有自己的finally
,这些块将在最后执行个人try
阻止所以是的,finally
最后执行,但仅连接到try
块。
所以给出以下片段:
try {
try {
throw null;
} finally {
System.out.println("Finally (inner)");
}
} catch (Throwable e) {
System.out.println("Catch (outer)");
}
Finally (inner)
Catch (outer)
观察:
(inner)
内,Finally
是最后一次(无论catch
是否成功)Catch (outer)
跟在Finally (inner)
之后,但那是因为Finally (inner)
嵌套在 try
(outer)
块内
同样,以下代码段:
try {
try {
throw null;
} catch (Throwable e) {
System.out.println("Catch (inner)");
} finally {
System.out.println("Finally (inner)");
throw null;
}
} catch (Throwable e) {
System.out.println("Catch (outer)");
}
Catch (inner)
Finally (inner)
Catch (outer)
答案 2 :(得分:7)
catch最终出现在同一个try-catch-finally范围之前。
test2在try2的try-catch-finally范围内没有捕获,所以它在离开范围之前完成了最终并落入了更高的捕获。
答案 3 :(得分:4)
因为finally
块总是在退出范围之前执行。调用test2()
后的事件序列如下:
test2()
中抛出了test2
没有catch
阻止,因此异常会传播到调用方。test2
有finally
块,因此会在从方法返回之前执行。catch
捕获异常。答案 4 :(得分:2)
因为, finally 是在try..catch块中执行的最后一个代码,无论是抛出,抛出然后处理,还是根本不抛出异常。
实际上,唯一一次最终将不被调用的是JVM在执行它之前是否退出,或者执行try代码的线程是否被终止或被中断。
回应评论: Java Description of finally
Note: If the JVM exits while the try or catch code is being executed,
那么finally块可能没有 执行。同样,如果线程 执行try或catch代码是 中断或杀死,终于 即使该块也可能无法执行 申请作为一个整体继续。
但是你是正确的,因为抛出了一个ThreadDeath异常,我找不到太多关于来自sun的冲突信息的细节。这可能是一个问题。
终于(请原谅双关语)@brainimus,如果你在最后并抛出异常,那么最终代码 正在被执行,我的观点是最终代码未执行的条件。
答案 5 :(得分:2)
尝试 - 捕获并最终用于避免程序因执行程序期间发生意外错误而终止程序的情况。
以下几点很重要......
1)一个块只有一次尝试......一个块的任意数量的catch语句,最后只有一个用于一个块的
2)最后是可选的。
3)catch也是可选的,但如果缺少catch语句,则最终必须出现。
4)对应于子例外的所有捕获必须出现在父异常的catch之前。
5)无论异常是否发生,finally块中出现的语句总是以一次排除的方式执行。
即。如果遇到System.out.exit()语句,则程序会立即终止,因此在这种情况下最终无法执行。
注意:即使在try块中出现一个return语句......然后也会执行finally中的代码。
答案 6 :(得分:0)
如果用方法代码替换函数,则得到:
public class Main {
static int a = 0;
public static void main(String[] args) {
try {
try {
throw new Exception();
}
catch (Exception e) {
// I catch only the *first* exception thrown
System.out.println(a + ": inner catch");
a++;
// let's go to the finally block
}
finally {
System.out.println(a + ": finally");
a++;
// we go on
}
System.out.println("---");
try {
throw new Exception();
}
finally {
// executed because at the same level
System.out.println(a + ": finally");
a++;
}
}
catch(Exception e) {
// I catch only the *second* exception thrown
System.out.println(a + ": outer catch");
a++;
}
}
第一个异常使catch块执行,然后执行第一个finally块。由于第一个捕获块,它在外层看不到。第二个异常是由外层的catch块拦截的,但是最后一个异常位于内层,首先执行。
答案 7 :(得分:0)
首先执行try块。如果try块中存在需要捕获的异常,则执行Catch。最后,无论是否存在异常,都会运行块。如果在try块中有return语句,那么在try块中返回之前,最后块执行,然后在try块中执行return。