zoukankan      html  css  js  c++  java
  • 你真的理解Java中的try/catch/finally吗?

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

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

    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()的结果:

    try
    finally
    return in finally

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

    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()的结果:

    try
    finally
    return in try

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

    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()的结果:

    try
    catch
    finally
    return in finally

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

    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()的结果:

    try
    catch
    finally
    return in catch

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

    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()的结果:

    try
    catch
    finally
    return in function

    小结

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

     

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

    例子1

    public static int test() {
       try {
           return 1;
      } finally {
           return 2;
      }
    }

    返回值:2

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

    附编译后的代码:

    public static int test() {
       try {
           boolean var0 = true;
           return 2;
      } finally {
          ;
      }
    }

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

    例子2

    public static int test() {
       int i;
       try {
           i = 3;
      } finally {
           i = 5;
      }
       return i;
    }

    返回值:5

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

    附编译后的代码:

    public static int test() {
       boolean var0 = true;
       byte i;
       try {
           var0 = true;
      } finally {
           i = 5;
      }
       return i;
    }

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

    例子3

    public static int test() {
       int i = 1;
       try {
           i = 3;
           return i;
      } finally {
           i = 5;
      }
    }

    返回值:3

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

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

    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

    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只能保证对象本身不可变,但无法保证对象内部状态不可变。

    附编译后的代码:

    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

    public static int test() {
        try {
            System.exit(0);
        } finally {
            return 2;
        }
    }

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

    附编译后的代码:

    public static int test() {
       try {
           System.exit(0);
           return 2;
      } finally {
          ;
      }
    }

    例子6

    public static int test() {
       try {
           while(true) {
              System.out.println("Infinite loop.");
          }
      } finally {
           return 2;
      }
    }

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

    附编译后的代码:

    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的执行顺序(最有说服力的总结)

  • 相关阅读:
    45 个非常有用的 Oracle 查询语句
    [转载]java图片缩放处理
    [转载]java图片缩放处理
    十步完全理解SQL
    十步完全理解SQL
    day04_20170521_函数(二)
    to disable the entity lazy load, The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
    wordpress mobile templates
    linq query, using int.parse to convert varchar to int while orderby
    appfabric 简单应用
  • 原文地址:https://www.cnblogs.com/xiaoxi666/p/10954787.html
Copyright © 2011-2022 走看看