返回
字节码剖析 try-return-finally 执行顺序
前端
2023-09-28 11:29:34
1. try-catch-finally语法的执行顺序
众所周知,Java中try-catch-finally代码块的执行顺序为:
- 首先执行try块中的代码
- 如果在try块执行期间发生了异常,那么立即终止try块的后续代码,执行匹配的catch块
- 无论是否有异常发生,finally块总会被执行
2. try-return-finally执行顺序的争议
但是,如果在try块中使用return语句返回了,那么finally块是否还会执行?这个问题在Java社区引起了激烈的争论。
正方观点认为:
- finally块总是会执行,即使在try块中使用了return语句
- 这是因为finally块的执行与try块中的异常无关,而是与方法调用或构造器调用相关
- 因此,无论是否发生异常,finally块总会被执行
反方观点认为:
- 如果在try块中使用了return语句,那么finally块不会被执行
- 这是因为return语句会立即终止当前方法或构造器的执行,而finally块是在方法或构造器执行结束后才执行的
- 因此,如果在try块中使用了return语句,那么方法或构造器的执行就会立即终止,而finally块也就不会被执行
3. 字节码剖析
为了弄清这个问题的真相,我们不妨对一段简单的Java代码进行字节码剖析。
public class FinallyTest {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
try {
return 1;
} finally {
System.out.println("finally");
}
}
}
使用javap命令对该代码进行字节码反编译,得到如下结果:
public class FinallyTest {
public static void main(String[] args);
Code:
0: invokestatic #2 // Method test:()I
3: invokestatic #3 // Method java/lang/System.out:println(I)V
6: return
private static int test();
Code:
0: iconst_1
1: ireturn
2: astore_0
3: aload_0
4: athrow
}
从反编译结果中,我们可以看到,test()方法的字节码指令序列如下:
- iconst_1:将整数1压入操作数栈
- ireturn:从方法中返回整数1,并将操作数栈清空
- astore_0:将异常对象压入局部变量表中的索引0处
- aload_0:从局部变量表中的索引0处加载异常对象
- athrow:将异常对象抛出
其中,iconst_1和ireturn指令位于try块中,astore_0、aload_0和athrow指令位于finally块中。
从字节码指令序列中,我们可以清楚地看到,try块中的代码确实会在finally块之前执行。但是,如果在try块中使用了return语句,那么finally块中的代码并不会被执行。
这是因为ireturn指令会立即终止方法的执行,而finally块是在方法执行结束后才执行的。因此,如果在try块中使用了return语句,那么方法的执行就会立即终止,而finally块也就不会被执行。
4. 结论
综上所述,我们可以得出结论:如果在try块中使用了return语句,那么finally块不会被执行。这是因为return语句会立即终止当前方法或构造器的执行,而finally块是在方法或构造器执行结束后才执行的。
因此,在编写代码时,我们需要注意,如果需要在try块中返回一个值,那么就不要在finally块中执行任何操作。否则,finally块中的代码将不会被执行。