执行流程
finally子句是异常捕获的一部分
try{
}catch(Exception e){
}finally{
}
三部分的执行顺序是try块检测并抛出异常,然后由catch子句捕获,最后执行finally子句。
try块必须有,catch和finally子句不一定全都必须,可以二选一,也可都有。
class TException extends Exception {}
public class FinallyWorks {
static int count = 0;
public static void main(String[] args) {
while (true) {
try {
if (count++ == 0) {
throw new TException();
}
System.out.println("No exception");
} catch (Exception e) {
System.out.println("TException");
} finally {
System.out.println("In finally clause");
if (count == 2) break;
}
}
}
}
//output:
TException
In finally clause
No exception
In finally clause
finally子句的作用是不论try和catch中的代码执行情况如何,它都会执行,断言的终止也会执行。(有一种情况特殊就是在try或者catch中执行System.exit(1);
,它会直接终止程序,从而让finally得不到执行)
try块中有return,finally子句还会执行吗?
答案是会,那么它在什么时候执行呢?看完你就知道了,下面详细讨论各种情况:
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(new Test().backInt());
}
int backInt() {
int i = 1;
try {
System.out.println("execute1");
return i;
} finally {
i = 2;
System.out.println("execute2");
}
}
}
//output
execute1
execute2
1
可以看出try块中即使存在return语句,finally子句还是执行了。但是输出的结果却是1,这是为什么?我们调试下看看
但是最后输出却是1,那不是finally中的操作没有效果了吗?
一切从编译文件入手,原来是这样啊!!!
好,现在看看它的编译文件,一切都知道了。
public class Test {
public Test() {
}
public static void main(String[] args) throws Exception {
System.out.println((new Test()).backInt());
}
int backInt() {
byte i = 1;
byte var2;
try {
System.out.println("execute1");
var2 = i;
} finally {
int i = true;
System.out.println("execute2");
}
return var2;
}
}
如果是对象呢,看下面这段代码:
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(new Test().backObject());
}
static Object object = new Object();
Object backObject() {
try {
System.out.println(object);
return object;
} finally {
object = new Object();
System.out.println(object);
}
}
}
//output:
java.lang.Object@33d4f6b4
java.lang.Object@6290be01
java.lang.Object@33d4f6b4
反编译文件:
public class Test {
static Object object = new Object();
public Test() {
}
public static void main(String[] args) throws Exception {
System.out.println((new Test()).backObject());
}
Object backObject() {
Object var1;
try {
System.out.println(object);
var1 = object;
} finally {
object = new Object();
System.out.println(object);
}
return var1;
}
}
看来都是一样的。
如果我改变返回对象其中的某个属性,最终能成功返回吗?答案是会的,看下面代码:
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(new Test().backObject());
}
static A object = new A();
A backObject() {
try {
System.out.println(object);
return object;
} finally {
object.i = 2;
System.out.println(object);
}
}
}
class A {
public int i = 1;
@Override
public String toString() {
return "" + i;
}
}
//output:
1
2
2
反编译文件:
public class Test {
static A object = new A();
public Test() {
}
public static void main(String[] args) throws Exception {
System.out.println((new Test()).backObject());
}
A backObject() {
A var1;
try {
System.out.println(object);
var1 = object;
} finally {
object.i = 2;
System.out.println(object);
}
return var1;
}
}
如果try块和finally子句都存在return语句
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(new Test().backObject());
}
static A object = new A();
A backObject() {
try {
System.out.println(object);
return object;
} finally {
object = new A();
System.out.println(object);
return object;
}
}
}
class A {
public int i = 1;
@Override
public String toString() {
return super.toString();
}
}
//output:
com.security.bcsx.A@71c2812
com.security.bcsx.A@498ab963
com.security.bcsx.A@498ab963
反编译文件:
public class Test {
static A object = new A();
public Test() {
}
public static void main(String[] args) throws Exception {
System.out.println((new Test()).backObject());
}
A backObject() {
try {
System.out.println(object);
A var1 = object;
} finally {
object = new A();
System.out.println(object);
return object;
}
}
}
看来最后返回的是finally子句返回的结果。其实这可能是种缺陷,举个例子说,如果在try块中抛出一个异常,可能希望在finally子句中释放锁定的资源,然而finally中又抛出了一个异常,那么最后方法的调用抛出的异常只会是finally子句的异常,try中的异常被屏蔽了,也许就找不到问题发生的地方了。
总结
如果只在try块中return,那么会先保存return的值,再执行finally,最后返回return保存的值。
如果都有return,那么try中的被屏蔽,只执行finally中的。