Java try catch finally详解(附带实例)
Java 语言提供了异常捕获的处理机制,可以帮助我们处理由异常引发的问题。一般情况下,异常捕获使用 try-catch 语句,其语法格式如下:
当有多个 catch 语句时,try 语句块里面的代码发生异常时,则会依次判断 catch 语句小括号里的异常类型是否和 try 里发生的异常匹配,匹配则成功捕捉,不匹配则继续向下进行匹配;如果只有一个 catch 语句,并且不匹配,则异常捕捉失败,程序依然会中断执行。
每个 catch 语句块可以处理的异常类型由异常处理器参数指定。所谓异常处理参数,就是下图所示的各种异常类型。

图 1 异常类的结构体系
接下来,用一个实例演示 try-catch 语句的用法。
从运行结果可发现,在 try 语句块中,当程序发生异常时,try 语句块中发生异常部分后面的代码不再被执行。在 catch 语句块中,系统对异常进行处理,处理完成后程序正常向后执行,不再因为发生异常而终止执行。
在实际开发中,finally 语句块用于关闭文件或释放其他系统资源。当然,也有一些例外情况,就是在 try-catch 语句块中执行 System.exit(0) 语句,表示退出当前的 Java 虚拟机,Java 虚拟机停止,程序中的任何代码都不会再执行。
接下来,通过案例来演示 finally 语句块的使用:
由此我们不难看出,不管程序是否发生异常,也不论在 try 和 catch 语句块中是否使用 return 语句结束,finally 语句块都会被执行。
另外,finally 是在 return 后面的表达式运算完成之后才执行的,此时并没有直接返回运算值,而是先将返回值保存(假设保存在了内存 A 中),finally 中的代码的执行不会影响方法的返回值,仍是在 finally 执行之前内存 A 中的值,因此方法返回值是在 finally 执行之前就已经确定的。
接下来,通过案例对上述情况进一步说明:
接下来,我们在 try 和 finally 语句块中加 return 语句进行测试:
try { 可能会产生异常的程序代码 } catch (异常类型 e) { 发生异常后处理的程序代码1 }catch (异常类型 e) { 发生异常后处理的程序代码2 } … catch (异常类型 e) { 发生异常后处理的程序代码n }上述语法中,try 的花括号里面放的是可能会产生异常的代码;一个异常代码块可以被一个或是多个 catch 语句进行捕获。
当有多个 catch 语句时,try 语句块里面的代码发生异常时,则会依次判断 catch 语句小括号里的异常类型是否和 try 里发生的异常匹配,匹配则成功捕捉,不匹配则继续向下进行匹配;如果只有一个 catch 语句,并且不匹配,则异常捕捉失败,程序依然会中断执行。
每个 catch 语句块可以处理的异常类型由异常处理器参数指定。所谓异常处理参数,就是下图所示的各种异常类型。

图 1 异常类的结构体系
接下来,用一个实例演示 try-catch 语句的用法。
public class Demo { public static void main(String[] args) { try { final int divide = divide(5, 0); // 调用divide方法 System.out.println(divide); } catch (ArithmeticException e) { // 注意异常类型,不匹配则捕获失败 System.out.println("捕获到了异常:" + e); // 异常处理语句 } System.out.println("异常捕获结束"); } // 下面的方法实现了两个整数相除 public static int divide(int x, int y) { int result = x / y; // 定义一个变量result,记录两个数相除的结果 return result; // 将结果返回 } }程序的运行结果如下:
捕获到了异常:java.lang.ArithmeticException: / by zero
异常捕获结束
从运行结果可发现,在 try 语句块中,当程序发生异常时,try 语句块中发生异常部分后面的代码不再被执行。在 catch 语句块中,系统对异常进行处理,处理完成后程序正常向后执行,不再因为发生异常而终止执行。
Java finally进行清理
事实上,一个完整的异常处理语句由 3 部分组成,即 try 语句块、catch 语句块和 finally 语句块,结构如下:try { 可能会产生异常的程序代码 }catch (异常类型 e) { 发生异常后处理的程序代码1 }catch (异常类型 e) { 发生异常后处理的程序代码2 } … catch (异常类型 e) { 发生异常后处理的程序代码n } finally { 最终执行的程序代码 }从语法上来讲,当异常处理机制结构中出现 catch 语句块时 finally 语句块是可选的,当包含 finally 语句块时 catch 语句块是可选的,二者可以同时存在,也可以只存在其一。与 catch 语句块可以出现多次不同,finally 语句块只能出现一次。
finally用来做什么
finally 是最终执行的语句块,无论 try-catch 语句块中是否发生异常,finally 语句块中的代码都会被执行。也就是说,当希望程序中的某些语句无论程序是否发生异常都执行时,可以将这些语句打包成 finally 语句块。在实际开发中,finally 语句块用于关闭文件或释放其他系统资源。当然,也有一些例外情况,就是在 try-catch 语句块中执行 System.exit(0) 语句,表示退出当前的 Java 虚拟机,Java 虚拟机停止,程序中的任何代码都不会再执行。
接下来,通过案例来演示 finally 语句块的使用:
public class Demo { public static void main(String[] args) { try { final int result = divide(5, 0); // 调用divide()方法 System.out.println(result); // 打印结果 } catch (ArithmeticException e) { System.out.println("捕获到了异常:" + e); return; } finally { System.out.println("开始执行finally块"); } System.out.println("异常捕获结束"); } // 下面的方法实现了两个整数相除 public static int divide(int x, int y) { int result = x / y; // 定义一个变量result,记录两个数相除的结果 return result; // 将结果返回 } }程序的运行结果如下:
捕获到了异常:java.lang.ArithmeticException: / by zero
开始执行finally块
由此我们不难看出,不管程序是否发生异常,也不论在 try 和 catch 语句块中是否使用 return 语句结束,finally 语句块都会被执行。
另外,finally 是在 return 后面的表达式运算完成之后才执行的,此时并没有直接返回运算值,而是先将返回值保存(假设保存在了内存 A 中),finally 中的代码的执行不会影响方法的返回值,仍是在 finally 执行之前内存 A 中的值,因此方法返回值是在 finally 执行之前就已经确定的。
接下来,通过案例对上述情况进一步说明:
public class Demo { public static int testReturn() { // 定义变量x int x = 1; // 定义变量x try { ++x; // ++在前时先运算 return x; // 返回结果 } finally { ++x; // ++在前时先运算 System.out.println("finally: " + x); // 打印在finally中的结果 } } public static void main(String[] args) { System.out.println("最终返回值: " + testReturn()); } }程序的运行结果如下:
finally:3
最终返回值:2
在finally中使用return
在 finally 中最好不要使用 return 语句,否则程序会提前退出,返回值不是 try 或 catch 语句块中保存的返回值。接下来,我们在 try 和 finally 语句块中加 return 语句进行测试:
public class Demo { public static String testReturn() { try { return "我是try中的return"; } finally { return "我是finally中的return"; } } public static void main(String[] args) { System.out.println("返回结果:" + testReturn()); } }程序的运行结果如下:
返回结果:我是finally中的return
程序最终输出的是 finally 中的 return 语句,而并不是 try 中的 return 语句,所以在 finally 中最好不要使用 return 语句。