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日更新

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

Try-Catch-Finally语句块执行问题的更多相关文章

  1. try...catch...finally语句块

    try-catch-finally语句主要是用来处理检查异常,捕获并处理,以及最后必须要执行的finally块. try-catch-finally语句入门: 1.try-catch-finally语 ...

  2. try catch finally语句块中存在return语句时的执行情况剖析

    2种场景 (1) try中有return,finally中没有return(注意会改变返回值的情形);(2) try中有return,finally中有return; 场景代码分析(idea亲测) 场 ...

  3. 顽强的的砂锅之——深究finally代码块与return语句的执行顺序!

    当问到finally代码块的执行顺序,就算刚刚学编程的小白都能毫不犹豫的说出答案:不管异常发生与否,finally语句块的代码一定会被执行!大体上这样讲是没有错,但是finally块中的代码一定会有效 ...

  4. Java中try catch finally语句中含return语句的执行情况总结-编程陷阱

    前言:有java编程基础的人对java的异常处理机制都会有一定了解,而且可能感觉使用起来也比较简单,但如果在try catch finally语句块中遇到return语句,开发者可能就会遇到一些逻辑问 ...

  5. Java静态语句块、语句块、构造方法执行顺序

    package com.imooc.practice; class Parent{ public Parent(){ System.out.println("Parent构造方法执行!&qu ...

  6. static{ }语句块详解

    static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法.举ge例子: public class Test { public static i ...

  7. 转 java中static{}语句块详解

    原文地址:http://blog.csdn.net/lubiaopan/article/details/4802430     感谢原作者! static{}(即static块),会在类被加载的时候执 ...

  8. java中static{}语句块详解

    static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法,下面我们详细的讨论一下该语句块的特性及应用. 一.在程序的一次执行过程中,stati ...

  9. 关于java的static语句块

    声明:转载请注明出处 static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法,下面我们详细的讨论一下该语句块的特性及应用. 一.在程序的一次 ...

随机推荐

  1. 文:你可以杀我,但你不能评价(judge)我

    原创 豆瓣影评:“现代战争启示录”豆友影评 2006-12-18 20:24:20 本文刊载于<豆瓣影评>豆友“芹泽虾饺菌”的影评  原文标题<剃刀边缘的疯狂> 文/芹泽虾饺菌 ...

  2. python中的随机模块random

    random模块是 python 中为随机数所使用的模块 ```import random # 随机生成0-1范围内的随机浮点数i = random.random()print(i) # 随机生成范围 ...

  3. itest(爱测试) 3.3.5 发布,开源敏捷测试管理 & BUG 跟踪管理软件

    v3.3.5 下载地址 :itest下载 itest 简介:查看简介 V3.3.5 有 6个功能增强,2个BUG修复 ,详情如下所述. 用户反馈并强烈要求增强的功能实现:    1: 测试用例管理可线 ...

  4. JAVA SE学习路径

  5. 3. Vue - 指令系统

    一.vue指令 (1) v-if // 条件判断 如果条件成立就在页面上生成一个标签并显示出来 (2) v-show //DOM中都存在只是显示与否 (3) v-for //注意 v-bind:key ...

  6. C++学习四 冒泡排序法的一些改进

    冒泡排序法需要两次扫描,所以从时间复杂度来说,是O(n2). 如果用图形表示,是这样的: 但是我们可以加以改进. 首先是,如果在排序中间,整个向量已经达到了有序状态,可以直接跳出来. 这样它的复杂度由 ...

  7. day50_9_11 bootstarp使用

    一.下载官网. https://www.bootcss.com/ 使用3版本 https://www.bootcdn.cn/ CDN搜索网址. 配置代码: <link rel="sty ...

  8. 【Eureka篇三】Eureka比Zookeeper好在哪里?(8)

    Eureka遵守AP,Zookeeper遵守CP RDBMS(oracle/mysql.sqlServer) ====> ACID, 关系型数据库遵循ACID原则 NoSQL(redis/mon ...

  9. CF1005F Berland and the Shortest Paths 最短路树计数

    问题描述 LG-CF1005F 题解 由题面显然可得,所求即最短路树. 所以跑出最短路树,计数,输出方案即可. \(\mathrm{Code}\) #include<bits/stdc++.h& ...

  10. CF915E Physical Education Lessons 珂朵莉树

    问题描述 CF915E LG-CF915E 题解 \(n \le 10^9\) 看上去非常唬人. 但是这种区间操作的题,珂朵莉树随便跑啊. \(\mathrm{Code}\) #include< ...