有return的情况下try catch finally的执行顺序
- 在遇到Exception 并且没有catch的情况下
finally
语句块没有执行 System.exit(0)
,终止了 Java 虚拟机的运行,finally
语句块没有执行
理解一下finally
The finally Block
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.
Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
它允许程序员避免因返回,继续或中断而意外绕过清理代码。 将清理代码放在finally块中始终是一种很好的做法,即使没有预期的例外情况也是如此。
注意:如果在执行try或catch代码时JVM退出,则finally块可能无法执行。 同样,如果执行try或catch代码的线程被中断或终止,则即使应用程序作为一个整体继续,finally块也可能无法执行。
举例分析
finally 语句块在 try 语句块中的 return 语句之前执行
public class FinallyTest {
public static void main(String[] args) {
System.out.println(new FinallyTest().test());
;
}
static int test() {
int x = 1;
try {
System.out.println("try");
return 0;
} finally {
System.out.println("Finally");
}
}
}
执行结果
try
Finally
0
说明 finally 语句块在 try 语句块中的 return 语句之前执行。
finally 语句块在 catch 语句块中的 return 语句之前执行
public class FinallyTest {
public static void main(String[] args) {
System.out.println(new FinallyTest().test());
;
}
static int test() {
int x = 1;
try {
System.out.println("try");
x /= 0;
return 0;
} catch (Exception e) {
System.out.println("catch");
return 1;
} finally {
System.out.println("Finally");
return 2;
}
}
}
输出结果
try
catch
Finally
2
看一下trick
code1
static int test() {
try {
return 0;
} finally {
return 1;
}
}
运行结果
1
code2
static int test() {
int i = 1;
try {
return i;
} finally {
i++;
}
}
运行结果
1
实际上,Java 虚拟机会把 finally 语句块作为 subroutine(对于这个 subroutine 不知该如何翻译为好,干脆就不翻译了,免得产生歧义和误解。)直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是,还有另外一个不可忽视的因素,那就是在执行 subroutine(也就是 finally 语句块)之前,try 或者 catch 语句块会保留其返回值到本地变量表(Local Variable Table)中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者(invoker)。请注意,前文中我们曾经提到过 return、throw 和 break、continue 的区别,对于这条规则(保留返回值),只适用于 return 和 throw 语句,不适用于 break 和 continue 语句,因为它们根本就没有返回值。
经典案例必看
public class FinallyTest {
public static void main(String[] args) {
System.out.println(new FinallyTest().test());
}
static String test() {
try {
System.out.println("try");
return test1();
} finally {
System.out.println("finally");
}
}
static String test1() {
System.out.println("test1()");
return "return test";
}
}
执行结果
try
test1()
finally
return test
为什么会这样执行呢?
return test1();
可以拆分成两个
String temp = test1();
return temp;
因此呢会先将try 代码块中的return放到局部变量表里,入栈,接着执行finally代码块的内容,最后return try中的内容
更经典的案例
public class FinallyTest {
public static void main(String[] args) {
System.out.println(new FinallyTest().test());
}
static String test() {
try {
System.out.println("try");
return test1();
} finally {
System.out.println("finally");
return "finally end";
}
}
static String test1() {
System.out.println("test1()");
return "return test";
}
}
运行结果
try
test1()
finally
finally end
因此可以分析
总结
先将try 代码块中的return的变量放到局部变量表里,操作数栈入栈,接着执行finally代码块的内容,(如果finally没有return语句的话,最后操作数栈出栈return try中的内容) (如果finally有return语句的话,最后return finally中的内容)