一些常识
finally语句块跟随try/catch语句块出现,常用于正常执行或异常捕获后的资源释放工作。一个范例是:
public static void main(String[] args) {
try {
System.out.println("exception thrown");
throw new Exception();
} catch (Exception e) {
System.out.println("exception caught");
} finally {
System.out.println("finally executed");
}
System.out.println("over");
}
控制台输出
exception thrown
exception caught
finally executed
over
上面的代码中,try语句块主动抛出异常后,由于异常能够被捕获,程序执行流首先转入相应的catch块,而后转入finally块中执行,最后再继续执行剩余的代码。这个过程是清晰的,但是,当遇到return语句时情况会稍微复杂一些
规律
① finally块中return的值会覆盖try/catch块中return的值
private static int test1() {
int a = 1;
try {
a++;
return a;
} finally {
a++;
return a;
}
}
private static int test2() {
int a = 1;
try {
throw new Exception();
} catch (Exception e) {
a++;
return a;
} finally {
a++;
return a;
}
}
test1与test2执行后均输出
3
② return的如果是基本数据类型,则在finally块中不可以修改已返回的数据,如果是引用类型,则可以
private static int test() {
int a = 1;
try {
a++;
return a;
} catch (Exception e) {
a++;
} finally {
a++;
}
return a;
}
由于a是基本数据类型,所以在finally块中修改a的值并不会影响try块中已经return的值,输出
2
private static String test() throws NoSuchFieldException, IllegalAccessException {
String a = "a";
try {
return a;
} finally {
Class<String> stringClass = String.class;
Field valueField = stringClass.getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(a, new char[]{'b'});
}
}
由于a是引用类型,所以还是有机会修改返回值的,输出
b
③ finally块中的代码并不是一定会执行的
public static void main(String[] args) {
System.out.println(test());
}
private static String test() {
try {
Runtime.getRuntime().exit(0);
return "exited";
} finally {
System.out.println("finally executed");
}
}
上面的代码不会有任何的输出