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

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

你真的理解Java中的try/catch/finally吗?的更多相关文章

  1. Java内存管理-你真的理解Java中的数据类型吗(十)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 作为Java程序员,Java 的数据类型这个是一定要知道的! 但是不管是那种数据类型最 ...

  2. [转载]java中try 与catch的使用

    留着以后看 原文地址:与catch的使用">java中try 与catch的使用作者:碌碌如玉 try{ //代码区 }catch(Exception e){ //异常处理 } 代码区 ...

  3. 【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析

    这一篇我们将会介绍java中try,catch,finally的用法 以下先给出try,catch用法: try { //需要被检测的异常代码 } catch(Exception e) { //异常处 ...

  4. 深入理解Java中的不可变对象

    深入理解Java中的不可变对象 不可变对象想必大部分朋友都不陌生,大家在平时写代码的过程中100%会使用到不可变对象,比如最常见的String对象.包装器对象等,那么到底为何Java语言要这么设计,真 ...

  5. 深入理解Java中的IO

    深入理解Java中的IO 引言:     对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务 < Thinking in Java >   本文的目录视图如下: ...

  6. 理解Java中的ThreadLocal

    提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...

  7. JDK学习---深入理解java中的LinkedList

    本文参考资料: 1.<大话数据结构> 2.http://blog.csdn.net/jzhf2012/article/details/8540543 3.http://blog.csdn. ...

  8. 【Java】深入理解Java中的spi机制

    深入理解Java中的spi机制 SPI全名为Service Provider Interface是JDK内置的一种服务提供发现机制,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用 ...

  9. 你真的理解Java 注解吗?

    你真的理解Java 注解吗? 1.什么是注解? 官方解释: Java 注解用于为 Java 代码提供元数据.作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的.Java ...

随机推荐

  1. Centos安装MySQL5.6并重置密码

    数据库配置 如果用的是自带的sqllite那么数据库就可以不动 安装MySQL5.6数据库 这里强烈建议用使用5.6, 5.7版本的数据库遇见了很多BUG 安装MySQL wget http://de ...

  2. C# 一个数组集合,任意组合,不遗漏,不重复

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  3. List.ForEach批量新增并发异常解决

    批量新增操作在业务系统中十分常见,尤其是主从表中对从表的批量处理.昨天在对wms主从表进行业务操作时使用了c#中list自带的函数ForEach对从表批量新增,代码如下: 在无并发的情况下接口请求正常 ...

  4. 求 无向图的割点和桥,Tarjan模板

    /* 求 无向图的割点和桥 可以找出割点和桥,求删掉每个点后增加的连通块. 需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重 */ const int MAXN = 10010; cons ...

  5. HDU 2897 bash 博弈变形

    一堆石子N个 每个人最少取P个 最多取Q个 最后取光的人输 问谁赢 X=N%(P+Q)  X=0则先手取Q个必胜 X<=P则后手胜 X>P则先手取P个必胜 #include <ios ...

  6. JDBC下

    存储过程名字前面一定要加一个sp,代表是存储过程 nofilter:没有过滤器,没有参数 )) BEGIN IF sp_name IS NULL OR sp_name='' THEN SELECT * ...

  7. 长春理工大学第十四届程序设计竞赛F Successione di Fixoracci——找规律&&水题

    题目 链接 题意:给出x数列的定义: $T_0 = a$ $T_1 = b$ $T_n = T_{n-2} \bigoplus T_{n-1} $ 求第 $n$ 项( $0 \leqslant a,b ...

  8. hdu 6074 Phone Call

    题 O∧O http://acm.hdu.edu.cn/showproblem.php?pid=6074 2017 Multi-University Training Contest - Team 4 ...

  9. Windows全屏代码--摘自Chrome

    变量定义: typedef struct SCREEN_INFO { DWORD dwStyle; DWORD dwExStyle; CRect rect; bool bMaximized; }Sre ...

  10. compile cmdow

    1. http://www.commandline.co.uk/ https://github.com/ritchielawrence/cmdow/tarball/master 2. g++ -O2 ...