你真的理解 Java 中的 try_catch_finally 吗?
- 2019 年 10 月 5 日
- 筆記

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; }
同样可以看出,编译器做了一些优化。
正是金九银十跳槽季,为大家收集了2019年最新的面试资料,有文档、有攻略、有视频。有需要的同学可以在公众号【Java知己】,发送【面试】领取最新面试资料攻略!
例子 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 不会被执行的情况
“不积跬步,无以至千里”,希望未来的你能:有梦为马 随处可栖!加油,少年!