前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你真的理解Java中的try/catch/finally吗?

你真的理解Java中的try/catch/finally吗?

作者头像
xiaoxi666
发布2019-06-01 14:19:30
6730
发布2019-06-01 14:19:30
举报
文章被收录于专栏:xiaoxi666的专栏xiaoxi666的专栏

看几个例子,回顾一下执行顺序

例子1 无异常,finally中的return会导致提前返回

代码语言:javascript
复制
public static String test() {
    try {
        System.out.println("try");
        return "return in try";
    } catch(Exception e) {
        System.out.println("catch");
        return "return in catch";
    } finally {
        System.out.println("finally");
        return "return in finally";
    }
}

调用test()的结果:

代码语言:javascript
复制
try
finally
return in finally

例子2 无异常,try中的return会导致提前返回

代码语言:javascript
复制
public static String test() {
    try {
        System.out.println("try");
        return "return in try";
    } catch(Exception e) {
        System.out.println("catch");
    } finally {
        System.out.println("finally");
    }
    return "return in function";
}

调用test()的结果:

代码语言:javascript
复制
try
finally
return in try

例子3 有异常,finally中的return会导致提前返回

代码语言:javascript
复制
public static String test() {
        try {
            System.out.println("try");
            throw new Exception();
        } catch(Exception e) {
            System.out.println("catch");
            return "return in catch";
        } finally {
            System.out.println("finally");
            return "return in finally";
        }
    }

调用test()的结果:

代码语言:javascript
复制
try
catch
finally
return in finally

例子4 有异常,catch中的return会导致提前返回

代码语言:javascript
复制
public static String test() {
    try {
        System.out.println("try");
        throw new Exception();
    } catch(Exception e) {
        System.out.println("catch");
        return "return in catch";
    } finally {
        System.out.println("finally");
    }
}

调用test()的结果:

代码语言:javascript
复制
try
catch
finally
return in catch

例子4 有异常,不会提前返回

代码语言:javascript
复制
public static String test() {
    try {
        System.out.println("try");
        throw new Exception();
    } catch(Exception e) {
        System.out.println("catch");
    } finally {
        System.out.println("finally");
    }
    return "return in function";
}

调用test()的结果:

代码语言:javascript
复制
try
catch
finally
return in function

小结

上面这几个例子,大多数人已经非常了解。同时也衍生出一些理论,比如不要在finally中return等,不再赘述。

再看几个例子,返回值是否符合你的预期?

例子1

代码语言:javascript
复制
public static int test() {
    try {
        return 1;
    } finally {
        return 2;
    }
}

返回值:2

说明:与我们上面的例子一致,finally中的return导致提前返回,try中的return1不会被执行。

附编译后的代码:

代码语言:javascript
复制
public static int test() {
    try {
        boolean var0 = true;
        return 2;
    } finally {
        ;
    }
}

可以看到编译器做过优化,同时验证了boolean类型在底层是用int实现的,但注意你在源码中直接给int行赋值true或false是不被允许的。

例子2

代码语言:javascript
复制
public static int test() {
    int i;
    try {
        i = 3;
    } finally {
        i = 5;
    }
    return i;
}

返回值:5

说明:执行try中的代码后,再执行finally中的代码,最终i被赋值为5,最后返回

附编译后的代码:

代码语言:javascript
复制
public static int test() {
    boolean var0 = true;
    byte i;
    try {
        var0 = true;
    } finally {
        i = 5;
    }
    return i;
}

同样可以看出,编译器做了一些优化。

例子3

代码语言:javascript
复制
public static int test() {
    int i = 1;
    try {
        i = 3;
        return i;
    } finally {
        i = 5;
    }
}

返回值:3

这个例子稍微有点意思,按我们通常的思维,应该还是返回5,毕竟finally中把i赋值为5了嘛,然后由try中的return返回。然而很不幸,返回值是3。

为什么呢?先看一下编译后的代码:

代码语言:javascript
复制
public static int test() {
    boolean var0 = true;
    byte var1;
    try {
        int i = 3;
        var1 = i;
    } finally {
        var0 = true;
    }
    return var1;
}

我们会发现,finally中的代码块不起作用。不知你是否想起一点:Java中是按值传递的,finally中的i只是一个局部变量,finally块执行完毕后,局部变量便不复存在。

接着看例子:

例子4

代码语言:javascript
复制
public static List test() {
    List<Integer> list = new ArrayList<>();
    try {
        list.add(1);
        return list;
    } finally {
        list.add(2);
    }
}

返回:包含1和2两个元素的List对象。

说明:这个例子中,基本类型int被替换为引用类型List,虽然list是按值传递,但它内部的状态可变(体现在这里,就是可以add元素)。扩展:finally只能保证对象本身不可变,但无法保证对象内部状态不可变。

附编译后的代码:

代码语言:javascript
复制
public static List test() {
    ArrayList list = new ArrayList();
    ArrayList var1;
    try {
        list.add(1);
        var1 = list; // 执行这一步操作后,var1和list指向同一个对象
    } finally {
        list.add(2);
    }
    return var1;
}

你现在应该觉得自己理解了,那么再来看两个例子:

例子5

代码语言:javascript
复制
public static int test() {
     try {
         System.exit(0);
     } finally {
         return 2;
     }
 }

该函数没有返回值。原因:jvm提前退出了。

附编译后的代码:

代码语言:javascript
复制
public static int test() {
    try {
        System.exit(0);
        return 2;
    } finally {
        ;
    }
}

例子6

代码语言:javascript
复制
public static int test() {
    try {
        while(true) {
           System.out.println("Infinite loop.");
        }
    } finally {
        return 2;
    }
}

由于try中的无限循环阻塞,永远执行不到finally中的代码块。

附编译后的代码:

代码语言:javascript
复制
public static int test() {
    try {
        while(true) {
            System.out.println("Infinite loop.");
        }
    } finally {
        ;
    }
}

小结

为了方便说明,只举了finally代码块的例子,catch代码块是类似的。

总结

执行顺序:

  1. try代码块中return前面的部分

  2. catch代码块中return前面的部分

  3. finally代码块中return前面的部分

  4. finally的return 或 catch的return 或 try的return。若前面的return被执行,会导致提前返回,同时后面的return被忽略。

  5. 方法的其他部分

变量:

  注意Java的按值传递规则

特殊情况:

  注意finally不会被执行的情况   

参考

Try-catch-finally-return clarification [duplicate]

有return的情况下try catch finally的执行顺序(最有说服力的总结)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-31 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 看几个例子,回顾一下执行顺序
    • 例子1 无异常,finally中的return会导致提前返回
      • 例子2 无异常,try中的return会导致提前返回
        • 例子3 有异常,finally中的return会导致提前返回
          • 例子4 有异常,catch中的return会导致提前返回
            • 例子4 有异常,不会提前返回
              • 小结
              • 再看几个例子,返回值是否符合你的预期?
                • 例子1
                  • 例子2
                    • 例子3
                      • 例子4
                        • 例子5
                          • 例子6
                            • 小结
                              • 总结
                              • 参考
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档