共计 4374 个字符,预计需要花费 11 分钟才能阅读完成。
前言
之前在刷笔试题和面试的时候经常会遇到或者被问到 try-catch-finally 语法块的执行顺序等问题,今天就抽空整理了一下这个知识点,然后记录下来。
正文
本篇文章主要是通过举例的方式来阐述各种情况,我这里根据 try-catch-finally 语法块分为两种大情况讨论:try-catch 语法块和 try-catch-finally 语句块,然后再在每种情况里再去具体讨论。
一、try-catch 语句块
我们可以看看下面程序:
public static void main(String[] args) {System.out.println(handleException0());
}
/**
* try,catch 都有 return
* @return
*/
private static String handleException0() {
try{System.out.println("try 开始");
String s = null;
int length = s.charAt(0);
System.out.println("try 结束");
return "try 块的返回值";
}catch (Exception e){System.out.println("捕获到了异常");
return "catch 的返回值";
}
}
执行结果:
try 开始
捕获到了异常
catch 的返回值
分析:程序首先执行 try 块里面的代码,try 块里面发现有异常,try 块后面的代码不会执行(自然也不会 return),然后进入匹配异常的那个 catch 块,然后进入 catch 块里面将代码执行完毕,当执行到 catch 里面的 return 语句的时候,程序中止,然后将此 return 的最终结果返回回去。
二、try-catch-finally 语句块
这种语法块我分为了 4 种情况讨论,下面进行一一列举。
1、第一种情况,try 块里面有 return 的情况,并且捕获到异常
例 1:
public static void main(String[] args) {String result = handleException1();
System.out.println(result);
}
private static String handleException1() {
try{System.out.println("try 开始");
String str = null;
int length = str.length();
System.out.println("try 结束");
}catch (Exception e){System.out.println("捕获到了异常");
}finally {System.out.println("finally 块执行完毕了");
}
return "最终的结果";
}
例 1 执行的结果如下:
try 开始
捕获到了异常
finally 块执行完毕了
最终的结果
例 2:
public static void main(String[] args) {String result = handleException2();
System.out.println(result);
}
private static String handleException2() {
try{System.out.println("try 开始");
String str = null;
int length = str.length();
System.out.println("try 结束");
return "try 块的返回值";
}catch (Exception e){System.out.println("捕获到了异常");
}finally {System.out.println("finally 块执行完毕了");
}
return "最终的结果";
}
例 2 的执行结果如下:
try 开始
捕获到了异常
finally 块执行完毕了
最终的结果
分析:首先 例 1 和 例 2 的结果是很显然的,当遇到异常的时候,直接进入匹配到相对应的 catch 块,然后继续执行 finallly 语句块,最后将 return 结果返回回去。
第二种情况:try 块里面有 return 的情况,但是不会捕获到异常
例 3:
思考:下面代码 try 语句块中有 return 语句,那么是否执行完 try 语句块就直接 return 退出方法了呢?
public static void main(String[] args) {String result = handleException3();
System.out.println(result);
}
private static String handleException3() {
try{System.out.println("");
return "try 块的返回值";
}catch (Exception e){System.out.println("捕获到了异常");
}finally {System.out.println("finally 块执行完毕了");
}
return "最终的结果";
}
例 3 的执行结果如下:
finally 块执行完毕了
try 块的返回值
分析 :例 3 的结果其实我们可以通过打断点的方式去看看程序的具体执行流程,通过 打断点 我们可以发现,代码先执行 try 块 里的代码,当执行到 return 语句的时候,handleException3 方法并没有立刻结束,而是继续执行 finally 块里的代码,finally 块里的代码执行完后,紧接着回到 try 块的 return 语句,再把最终结果返回回去,handleException 方法执行完毕。
第三种情况:try 块和 finally 里面都有 return 的情况
例 4:
public static void main(String[] args) {System.out.println(handleException4());
}
/**
* 情况 3:try 和 finally 中均有 return
* @return
*/
private static String handleException4() {
try{System.out.println("");
return "try 块的返回值";
}catch (Exception e){System.out.println("捕获到了异常");
}finally {System.out.println("finally 块执行完毕了");
return "finally 的返回值";
}
// return "最终的结果";// 不能再有返回值
}
例 4 的执行结果:
finally 块执行完毕了
finally 的返回值
分析 :需要注意的是,当 try 块和 finally 里面都有 return 的时候,在 try/catch/finally 语法块之外不允许再有 return 关键字。我们还是通过在程序中 打断点的方式 来看看代码的具体执行流程。代码首先执行 try 块 里的代码,当执行到 return 语句的时候,handleException4 方法并没有立刻结束,而是继续执行 finally 块里的代码,当发现 finally 块里有 return 的时候,直接将 finally 里的返回值(也就是最终结果)返回回去,handleException4 方法执行完毕。
第四种情况:try 块,catch 块,finally 块都有 return
例 5:
public static void main(String[] args) {System.out.println(handleException5());
}
/**
* 情况 4:try,catch,finally 都有 return
* @return
*/
private static String handleException5() {
try{System.out.println("try 开始");
int[] array = {1, 2, 3};
int i = array[10];
System.out.println("try 结束");
return "try 块的返回值";
}catch (Exception e){e.printStackTrace();// 这行代码其实就是打印输出异常的具体信息
System.out.println("捕获到了异常");
return "catch 的返回值";
}finally {System.out.println("finally 块执行完毕了");
return "finally 的返回值";
}
// return "最终的结果";
}
例 5 的执行结果:
try 开始
捕获到了异常
finally 块执行完毕了
finally 的返回值
java.lang.ArrayIndexOutOfBoundsException: 10at com.example.javabasic.javabasic.ExceptionAndError.TryCatchFinally.handleException5(TryCatchFinally.java:25) at com.example.javabasic.javabasic.ExceptionAndError.TryCatchFinally.main(TryCatchFinally.java:14)
分析:程序首先执行 try 块里面的代码,try 块里面发现有异常,try 块后面的代码不会执行(自然也不会 return),然后进入匹配异常的那个 catch 块,然后进入 catch 块里面将代码执行完毕,当执行到 catch 里面的 return 语句的时候,程序不会马上终止,而是继续执行 finally 块的代码,最后执行 finally 里面的 return,然后将此 return 的最终结果返回回去。
总结
其实,我们通过以上例子我们可以发现,不管 return 关键字在哪,finally 一定会执行完毕。理论上来说 try、catch、finally 块中都允许书写 return 关键字,但是执行优先级较低的块中的 return 关键字定义的返回值将覆盖执行优先级较高的块中 return 关键字定义的返回值。也就是说 finally 块中定义的返回值将会覆盖 catch 块、try 块中定义的返回值;catch 块中定义的返回值将会覆盖 try 块中定义的返回值。
再换句话说如果在 finally 块中通过 return 关键字定义了返回值,那么之前所有通过 return 关键字定义的返回值都将失效——因为 finally 块中的代码一定是会执行的。
最后,最近很多小伙伴找我要Linux 学习路线图,于是我根据自己的经验,利用业余时间熬夜肝了一个月,整理了一份电子书。无论你是面试还是自我提升,相信都会对你有帮助!
免费送给大家,只求大家金指给我点个赞!
电子书 | Linux 开发学习路线图
也希望有小伙伴能加入我,把这份电子书做得更完美!
有收获?希望老铁们来个三连击,给更多的人看到这篇文章
推荐阅读:
- 干货 | 程序员进阶架构师必备资源免费送
- 神器 | 支持搜索的资源网站