Try-Catch-Finally语句块执行问题

记录一个今天某公司的面试问题,其实我问题回答对了,但是面试官问我动手验证过没有,这还真没有,纯理论,被怼惨了,希望自己能变得更强大。

Try-Catch-Finally语句块执行问题。

一起来看下面这串代码:

public class TryCatchFinally {
public static void main(String[] args){
System.out.println(get());
}
private static int get(){
try{
System.out.println("Try语句块");
return 0;
}catch (Exception e){
System.out.println("Catch语句块");
return 1;
}finally {
System.out.println("Finally语句块");
return 2;
}
}
}

程序运行结果:

再来看下面这串代码:

public class TryCatchFinally {
public static void main(String[] args){
System.out.println(get());
}
private static int get(){
try{
System.out.println("Try语句块");
throw new Exception();
}catch (Exception e){
System.out.println("Catch语句块");
return 1;
}finally {
System.out.println("Finally语句块");
return 2;
}
}
}

程序运行结果:

总结:

通过上面两个例子可以看出:

  • 无论是否在 try 语句块中抛出异常,finally语句块中的内容都会得到执行。
  • 只有 try 语句块中抛出异常了,catch语句块中的内容才会得到执行。
  • 但无论在 try 和 catch 语句块中是否有返回语句,finally 语句都会得到执行,并且当 finally 语句中有 return 语句,try 和 catch 语句中的 return 语句都无法得到执行。

当然去掉 finally 中的 return 语句,try 或 catch 中的 return 语句又可以得到执行,这个可以直接在上面那个程序进行试验。

同时 finally 语句块中包含 return 语句,编译器也会给出警告:finally block can not complete normally。

这是因为 finally 的 return 语句覆盖了前面的 return 语句,是一种不合理的做法,尽量不要在 finally 中使用 return。

补充一点:

为什么 finally 语句始终都会得到执行,这里推荐一篇博客:https://blog.csdn.net/neosmith/article/details/48093427

简单来说就是 JVM 将 finally 语句块中的东西都复制了一遍到 try 和 catch 语句块中,确保 finally语句块必定会得到执行。

补充(2019/9/22)

今天又发现一个问题,来更新一下,看下面这串代码:

public class TestMain {
public int test(){
int a=0;
try{
a++;
throw new Exception("故意的");
}catch (Exception e){
a++;
return a;
}finally {
a++;
System.out.println("a1="+a);
}
}
public static void main(String[] args){
int a=new TestMain().test();
System.out.println("a2="+a);
}
}

可以看到这个地方在test中打印的a值为 3 ,但返回值却是 2 ,这个地方又难住了,特地查了一下资料,有这么一句话:

“Java 虚拟机会把 finally 语句块作为 subroutine直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是,还有另外一个不可忽视的因素,那就是在执行 subroutine之前,try 或者 catch 语句块会保留其返回值到本地变量表中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者。”

也就是说这里是在 a++ 和 return 之间插入了 finally语句块,但是在执行 finally 语句块之前,先对 a 的值进行了保存,而之后的 finally语句块中对 a 进行的修改只是一个值传递,并没有对变量表中的 a 的值进行修改,所以也就是为什么在 finally 中 a 值为 3,而返回值 a 却为 2。

当然这里如果将 a 改成一个对象,对对象中的某个值进行修改,也就是进行引用传递,则会对返回值进行修改。

这里推荐一篇博客:https://www.jianshu.com/p/011062aaa855

2019/9/22日更新

吾生也有涯,而知也无涯。

最新文章

  1. 当程序以Windows Services形式启动时当前路径不对
  2. debian下NTFS分区无法访问解决
  3. ubuntu安装配置elasticSearch(vagrant)
  4. [转]ASP.NET 2.0中GridView无限层复杂表头的实现
  5. Spring 集成 RMI
  6. 【XDU1144】合并模板
  7. iOS xcode 8 注释快捷键
  8. 转:探讨android更新UI的几种方法
  9. hbase 架构
  10. FZU2176(二维线段树+dfs)
  11. HDU6191(01字典树启发式合并)
  12. LOJ121 「离线可过」动态图连通性
  13. linux 换源
  14. git tag 用法 功能作用
  15. 关于macroblaze的一些理解(更新中)
  16. 快排 - 快速排序算法 (Chinar出品 简单易懂)
  17. mysql的checkpoint
  18. loadrunner脚本001
  19. hadoop的五个守护进程【转】
  20. 【C++程序员学 python】python 的文件类型

热门文章

  1. crawlscrapy简单使用方法
  2. MySQL日常使用遵循的规范建议
  3. [Go] vscode配置Go环境
  4. CodeForces - 1236B (简单组合数学)
  5. C学习笔记(3)---作用域,数组, (少量指针入门)
  6. Excel中的一列数据变成文本的一行数据
  7. 自定义MVC二
  8. localStorage在不同页面之间的设置值与取值--加密 localStorage与解密localStorage
  9. 第一周-调用weka算法进行数据挖掘
  10. [C2P2] Andrew Ng - Machine Learning