例1:
public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
return t;
} catch (Exception e) {
// result = "catch";
t = "catch";
return t;
} finally {
t = "finally";
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}
首先程序执行try语句块,把变量t赋值给try,由于没有发现异常,接下来执行finally语句块,把变量t赋值为finally,然后return t,则t的值是finally,最后t的值就是finally,但是实际结果为try。通过看这段代码编译出来的class对应的字节码,看虚拟机内部是如何执行的。
通过字节码,我们发现,在try语句的return块中,return返回的引用变量(t是引用类型)并不是try语句外定义的引用变量t,而是系统重新定义了一个局部引用t1,这个引用指向了引用t对应的值,也就是try,即使在finally语句中把引用t指向了值finally,因为return的返回引用已经不是t,所以引用t的对应的值和try语句中的返回值无关了。
例2:
public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
return t;
} catch (Exception e) {
// result = "catch";
t = "catch";
return t;
} finally {
t = "finally";
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}
这里面稍微改了第一段代码,只是在finaliy语句块里面加入了一个return t的表达式
这次返回的是finally的return。
我们发现try语句中return语句给忽略。可能jvm认为一个方法里面有两个return语句并没有太大的意义,所以try中的return语句给忽略了,直接起作用的是finally中的return语句,所以这次返回的是finally.
例3
public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
return t;
} finally {
t = "finally";
// System.out.println(t);
// return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}
这里面try语句里面会抛出java.lang.NumberFormatException,所以程序会先执行catch语句中的逻辑,t赋值为catch,在执行return之前,会把返回值保存到一个临时变量t1,执行finally的逻辑,t赋值为finally,但是返回值是t1,所以变量t的值和返回值已经没有关系了,返回的是catch.
例4
public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
return t;
} finally {
t = "finally";
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}
这个和例2类似,最后返回finally里的t
例5
public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
Integer.parseInt(null);
return t;
} finally {
t = "finally";
//return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}
这个例子在catch语句块添加了Integer.parser(null)语句,强制抛出了一个异常,然后finally语句块里面咩有return语句。继续分析一下,由于try语句抛出异常,程序进入catch语句块。catch语句块又抛出一个异常,说明catch语句要退出,则执行finally语句块,对t进行赋值。然后catch语句块里面抛出异常。结果抛出java.lang.NumberFormatException
异常。
例6
public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
Integer.parseInt(null);
return t;
} finally {
t = "finally";
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}
这个例子里面finally语句里面有return语句块。所以会执行finally里面的return
对以上所有的例子进行总结
1 try、catch、finally语句中,在如果try语句有return语句,则返回的之后当前try中变量此时对应的值,此后对变量做任何的修改,都不影响try中return的返回值
2 如果finally块中有return 语句,则返回try或catch中的返回语句忽略。
3 如果finally块中抛出异常,则整个try、catch、finally块中抛出异常
所以使用try、catch、finally语句块中需要注意的是
1 尽量在try或者catch中使用return语句。通过finally块中达到对try或者catch返回值修改是不可行的。
2 finally块中避免使用return语句,因为finally块中如果使用return语句,会显示的消化掉try、catch块中的异常信息,屏蔽了错误的发生
3 finally块中避免再次抛出异常,否则整个包含try语句块的方法回抛出异常,并且会消化掉try、catch块中的异常