执行流程
- try中没有异常(不到catch中):
- finally中无return:
- 返回的值是在try中该变量的值,与finally中赋值与否 无关
- finally中有return:
- 返回finally中的值,与try中的无关
- 返回finally中的值,与try中的无关
- finally中无return:
- try中有异常(到catch中去执行):
- finally中无return
- 返回的值是在catch中该变量的值,与finally中赋值与否 无关
- finally中有return:
- 返回finally中的值,与catch中的无关
- finally中无return
综上:如果finally块中有return 语句,则try或catch中的返回语句无效。
提问:这么复制的执行流程,使用起来如何才能避免被坑?
在《阿里巴巴Java开发手册》中强制要求 不要在 finally 块中使用 return ,try 块中的 return 语句执行成功后,并不马上返回,而是继续执行 finally 块中的语句,如果此处存在 return 语句,则在此直接返回,无情丢弃掉 try 块中的返回点。
代码用例
//第一种情况
@Test
public void tryCatchFinallyTest(){
System.out.println(TestTryCatchFinally.tryCatchFinally());//in finally
System.out.println(TestTryCatchFinally.tryCatchFinally1());//in try
}
static String tryCatchFinally(){
String s;
try {
s="in try";
return s;
}catch (Exception e){
s="in catch";
return s;
}finally {
s="in finally";
return s;
}
}
static String tryCatchFinally1(){
String s;
try {
s="in try";
return s;
}catch (Exception e){
s="in catch";
return s;
}finally {
s="in finally";
}
}
//第二种情况
@Test
public void tryCatchFinallyTest(){
System.out.println(TestTryCatchFinally.tryCatchFinally());//in finally
System.out.println(TestTryCatchFinally.tryCatchFinally1());//in catch
}
static String tryCatchFinally(){
String s;
try {
s="in try";
int i=1/0;
return s;
}catch (Exception e){
s="in catch";
return s;
}finally {
s="in finally";
return s;
}
}
static String tryCatchFinally1(){
String s;
try {
s="in try";
int i=1/0;
return s;
}catch (Exception e){
s="in catch";
return s;
}finally {
s="in finally";
}
}
JDK 7后的try-with-resources介绍及用例
try-with-resources 可以自动完成像 finally 块中对资源关闭的动作,但前提是对应的资源类实现了 AutoCloseable 接口
@Test
public void tryWithResource() {
try (Connection temp = new Connection()) {
temp.sentData();
//sentData method
//close method
} catch (Exception e) {
e.printStackTrace();
}
}
class Connection implements AutoCloseable {
public void sentData() {
System.out.println("sentData method");
}
@Override
public void close() throws Exception {
System.out.println("close method");
}
}
编译后的 .class 文件
@Test
public void tryWithResource() {
try {
Connection temp = new Connection();
Throwable var2 = null;
try {
temp.sentData();
} catch (Throwable var12) {
var2 = var12;
throw var12;
} finally {
if (temp != null) {
if (var2 != null) {
try {
temp.close();
} catch (Throwable var11) {
var2.addSuppressed(var11);
}
} else {
temp.close();
}
}
}
} catch (Exception var14) {
var14.printStackTrace();
}
}
其原理在编译后的文件中可以看到,自动为我们生成了 finally 代码块来完成关闭功能。
var2.addSuppressed(var11); 的作用
addSuppressed的使用,是为了避免在抛出多个异常的情况下,最上层异常会覆盖下层异常,导致下层抛出的异常消失,进而导致异常定位失败的情况。使用 addSuppressed 可以把多层的异常全部显示出来,方便对异常的定位。
必须使用finally的情况
- 必须回收自定义的 ThreadLocal 变量,因为在多线程环境下,大量的 ThreadLocal 变量会导致内存泄漏或后续业务逻辑的问题,需要在 finally 中回收(使用 ThreadLocal.remove() 方法)