文档章节

try-catch-finally

tsmyk0715
 tsmyk0715
发布于 10/18 22:04
字数 1772
阅读 8
收藏 0
JDK

try-catch-finally

一.执行顺序

 try-catch-finally 包含的代码块,当 try 里面的代码出现异常的时候,会进入 catch 中,finally 代码块则在最后被执行,即 无论是否出现异常,finally 里面的代码块都会被执行,但是如果 try 和 finally ,catch 和 finally 或 try , catch,  finally 中都有 return 语句的话,它的返回值该是多少呢?接下来看下每种情况的输出如何:

用例1:只有 try 里面有 return 语句

    public static int test1(){
        int i = 1;
        try {
            return i+5;
        }catch (Exception e){
            System.out.println("异常");
        }finally {

        }
        return i;
    }

输出:6

结论:只有 try 里面有 return 语句,则直接返回。

用例2:只有 try 里面有 return 语句,但是在 finally 里面对返回的值进行了修改,则应该返回什么呢?

    public static int test(){
        int i = 1;
        try {
            i++;
            return i;
        }catch (Exception e){
            System.out.println("异常");
        }finally {
            i++;
        }
        return i;
    }

输出:2

上面的代码,finally 一定会被执行,当执行完 finally 之后,i 的值变为了 3, 但是,返回的却还是 2,debug 跟踪如下:

当执行完 try 语句后,i 为 2:

接下来会执行 finally,之后, i 变为 3:

最终返回的结果还是 2,也就是说,当执行完 finally 中的代码后,还会进入到 try 中进行返回,且返回的是 finally 修改之前的值,

结论:只有 try 里面有 return 语句的时候,finally 里面对 return 值的修改将不会影响返回值

用例3:try,  finally 中都有 return 语句

    public static int test(){
        int i = 1;
        try {
            i++;
            return i;
        }catch (Exception e){
            System.out.println("异常");
        }finally {
            i++;
            return i;
        }
    }

输出:3

如上述代码所示,当 try 和 finally 中都有 return 语句的时候,finally 中的 return 会覆盖 try 中的 return

结论:当 try 和 finally 中都有 return 语句的时候,finally 中的 return 会覆盖 try 中的 return,方法的返回值以 finally 中返回的为准。

用例4:当只有 try 和 finally 有 return  语句,且 try 中抛异常

    public static int test(){
        int i = 1;
        try {
            i = i / 0;
            return i;
        }catch (Exception e){
            
        }finally {
            i++;
            return i;
        }
    }

输出:2

结论:当 try 中抛异常后,会进入到 catch 中,最后会进入 finally 中进行返回。

用例5:当只有 try 和 finally 有 return  语句,且 try 中抛异常,在 catch 中对值进行修改:

    public static int test(){
        int i = 1;
        try {
            i = i / 0;
            return i;
        }catch (Exception e){
            i++;
        }finally {
            i++;
            return i;
        }
    }

输出:3

结论:方法以 finally 中的返回值为准。

用例6:当只有 try 和 catch 中有 return 语句时候:

try 中无异常:

    public static int test(){
        int i = 1;
        try {
            return i;
        }catch (Exception e){
            i++;
            return i;
        }finally {
            i++;
        }
 输出:1

try 中有异常:

      public static int test(){
        int i = 1;
        try {
            i = i / 0;
            return i;
        }catch (Exception e){
            i++;
            return i;
        }finally {
            i++;
        }
    
输出:2

结论:当 只有 try 和 catch 中有 return 语句的时候,如果 try 中没有抛异常,则返回 try 中的值,如果 try 中抛异常,则返回 catch 中的值,同用例2一样,finally 中对返回的值进行修改,则还是返回修改之前的值,修改无效。

用例7:try,catch 和 finally 中都有 return 语句:

    public static int test(){
        int i = 1;
        try {
            i = i / 0;
            return i;
        }catch (Exception e){
            i++;
            return i;
        }finally {
            i++;
            return i;
        }
    }

输出:3

结论:以 finally 中的返回值为准。

总结

1.当 try 中抛异常的时候,会进入 catch 中

2.finally 块中无论是否抛异常都会被执行

3.当只有 try  中或者 catch 中有 return 语句的时候,finally 中对返回值的修改将无效,还是返回修改之前的值。

4.只要 finally 中有 return 语句,则方法的返回值将以 finally 中返回的为准。即 finally 中的 return 将会覆盖 try 中的 return 或 catch 中的 return。

JDK 1.7 后的变化

在 try-catch-finally 中,一般需要在 finally 中进行一些资源的清理工作。在 JDK 1.6 之前的,是必须在 finally 中进行清理的,但是在 JDK 1.7 之后,提供了 try-catch-resource 语法。

JDK 1.7 以前的写法如下:

    public static void test() throws IOException {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("a.txt");
            fis.read();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }finally {
            if (fis != null){
                fis.close();
            }
        }
    }

如上代码所示,如果在 try 中调用 read() 抛出异常,在 finally 中 调用 close() 也出现异常,则返回会向外抛出哪个异常呢?下面来试验一下:

首先声明一个方法抛出异常:

class MyFileInputStream implements AutoCloseable{

    public void read() throws Exception{
        throw new Exception("read() 出现异常");
    }
    @Override
    public void close() throws Exception {
        throw new Exception("close() 出现异常");
    }
}

测试:

public class Main {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        try{
            test();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void test() throws Exception {
        MyFileInputStream fis = null;
        try {
            fis = new MyFileInputStream();
            fis.read();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }finally {
            if (fis != null){
                fis.close();
            }
        }
    }
}

test()  方法会抛出,异常打印如下:

java.lang.Exception: close() 出现异常
	at myspringboot.myspringboot.other.MyFileInputStream.close(Main.java:40)
	at myspringboot.myspringboot.other.Main.test(Main.java:27)
	at myspringboot.myspringboot.other.Main.main(Main.java:12)

可以看到,方法最终抛出的异常将以 finally 中抛出的异常为准,在 try 中抛出的异常被 “吃掉” 了。

在 JDK 1.7 之后,JDK 提供可 try-catch-resource 的语法糖,写法如下:

    public static void test(){
        try (MyFileInputStream mfis = new MyFileInputStream()) {
            mfis.read();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

将需要关闭的资源写在 try 后面的括号里面,这样 JDK 就会自动的调用资源的close() 方法关闭资源,但是,要关闭的资源需要实现 AutoCloseable或者Closeable接口。

采用这种写法,出现异常的时候,方法会抛出哪个异常呢?try 里面的 还是 close() 里面的呢?接下来看下:

执行上述方法,异常打印如下:

java.lang.Exception: read() 出现异常
	at myspringboot.myspringboot.other.MyFileInputStream.read(Main.java:45)
	at myspringboot.myspringboot.other.Main.test(Main.java:21)
	at myspringboot.myspringboot.other.Main.main(Main.java:12)
	Suppressed: java.lang.Exception: close() 出现异常
		at myspringboot.myspringboot.other.MyFileInputStream.close(Main.java:49)
		at myspringboot.myspringboot.other.Main.test(Main.java:22)
		... 1 more

可以看到,方法抛出的异常是在 try 中抛出 的那个异常,刚好和之前的相反;但是 JDK 自动调用 close() 方法出现的异常也会跟在后面,也就是说,try中的异常和 close() 中的异常都会往外抛。

如果我们想获取 close() 抛出的异常,即第二个异常,怎么获取呢?可以通过 getSuppressed() 方法来获取:

    public static void test(){
        try (MyFileInputStream mfis = new MyFileInputStream()) {
            mfis.read();
        }catch (Exception e){
            System.out.println(e.getMessage());
            System.out.println((e.getSuppressed())[0].getMessage());
            e.printStackTrace();
        }
    }

异常打印如下:

read() 出现异常
close() 出现异常
java.lang.Exception: read() 出现异常
	at myspringboot.myspringboot.other.MyFileInputStream.read(Main.java:47)
	at myspringboot.myspringboot.other.Main.test(Main.java:21)
	at myspringboot.myspringboot.other.Main.main(Main.java:12)
	Suppressed: java.lang.Exception: close() 出现异常
		at myspringboot.myspringboot.other.MyFileInputStream.close(Main.java:51)
		at myspringboot.myspringboot.other.Main.test(Main.java:22)
		... 1 more

反编译该 class 文件如下:

    public static void test() {
        try {
            MyFileInputStream mfis = new MyFileInputStream();
            Throwable var1 = null;
            try {
                mfis.read();
            } catch (Throwable var11) {
                var1 = var11;
                throw var11;
            } finally {
                if (mfis != null) {
                    if (var1 != null) {
                        try {
                            mfis.close();
                        } catch (Throwable var10) {
                            var1.addSuppressed(var10);
                        }
                    } else {
                        mfis.close();
                    }
                }
            }
        } catch (Exception var13) {
            var13.printStackTrace();
        }
    }

从上述的反编译出来的代码可以看到,try-catch-resource 中 资源的 close() 方法最终也是会在 finally 中进行关闭。只不过,JDK 包装了一层,使用起来更加简洁。此外,还可以看到,当出现异常的时候,只有 try 向外 throw 异常,而 close() 出现的异常,只会添加到 try 抛出的异常后面(addSuppressed)。

 

© 著作权归作者所有

共有 人打赏支持
tsmyk0715
粉丝 34
博文 67
码字总数 148701
作品 0
成都
程序员
私信 提问
try catch finally 顺序执行

结论: 1、不管有木有出现异常,finally块中代码都会执行; 2、当try和catch中有return时,finally仍然会执行; 3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,...

ForingY
2016/02/18
44
0
java异常小结

一、java中异常的分类: 1.Error 当程序发生不可控的错误时,通常做法是通知用户并中止程序的执行。与异常不同的是Error及其子类的对象不应被抛出。 Error是throwable的子类,代表编译时间和...

hello菜bird
2016/09/02
44
0
asp.net中try catch finally中含有return时的执行顺序

1、try{} catch(){}finally{} return; 显然程序按顺序执行。 2、try{ return; }catch(){} finally{}return; (1)、程序执行try块中return之前(包括return语句中的表达式运算)代码; (2)、再...

学习也休闲
2015/09/29
269
0
Java中try、catch、finally

面试的笔试常涉及的问题: 有return的情况下try、catch、finally的问题。 结论    1、不管有没有异常,finally中的代码都会执行    2、当try、catch中有return时,finally中的代码依然会...

YuanyuanL
03/06
0
0
try catch finally中return

1、 不管有木有出现异常,finally块中代码都会执行; 2、当try和catch中有return时,finally仍然会执行; 3、当try和catch中有return时,finally也有return时,程序执行finally块中的return。...

LYQ1990
2016/04/26
22
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周二乱弹 —— 哥们之间报恩的想法被上帝实现了

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 小小编辑:推荐歌曲《消愁》 《消愁》- 毛不易 手机党少年们想听歌,请使劲儿戳(这里) @过遥 :周一的早上就应该用来补觉,太困了 周末不想...

小小编辑
57分钟前
195
7
MariaDB 服务器在 MySQL Workbench 备份数据的时候出错如何解决

服务器是运行在 MariaDB 10.2 上面的,在使用 MySQL Workbench 出现错误: mysqldump: Couldn't execute 'SELECT COLUMN_NAME, JSON_EXTRACT(HISTOGRAM, '$."number-of-buckets-specified"'......

honeymose
今天
3
0
apache顶级项目(二) - B~C

apache顶级项目(二) - B~C https://www.apache.org/ Bahir Apache Bahir provides extensions to multiple distributed analytic platforms, extending their reach with a diversity of s......

晨猫
今天
7
0
day152-2018-11-19-英语流利阅读

“超级食物”竟然是营销噱头? Daniel 2018-11-19 1.今日导读 近几年来,超级食物 superfoods 开始逐渐走红。不难发现,越来越多的轻食餐厅也在不断推出以超级食物为主打食材的健康料理,像是...

飞鱼说编程
今天
22
1
SpringBoot源码:启动过程分析(二)

接着上篇继续分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 一样的,我们先把时序图贴上来,方便理解: 二.源码分析 回顾一下,前面我们分析到了下...

Jacktanger
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部