“该讲 try-catch-finally 了。”我说,“try 关键字后面会跟一个大括号 ,我们把一些可能发生异常的代码放到大括号里;try 块后面一般会跟 catch 块,用来处理发生异常的情况;当然了,异常不一定会发生,为了保证发不发生异常都能执行一些代码,就会跟一个 finally 块。”

    “具体该怎么用呀,二哥?”三妹问。

    “别担心,三妹,我一一来说明下。”我说。

    try 块的语法很简单:

    “注意啊,三妹,如果一些代码确定不会抛出异常,就尽量不要把它包裹在 try 块里,因为加了异常处理的代码执行起来要比没有加的花费更多的时间。”

    catch 块的语法也很简单:

    1. try{
    2. // 可能发生异常的代码
    3. }catch (exception(type) e(object)){
    4. // 异常处理代码
    5. }

    一个 try 块后面可以跟多个 catch 块,用来捕获不同类型的异常并做相应的处理,当 try 块中的某一行代码发生异常时,之后的代码就不再执行,而是会跳转到异常对应的 catch 块中执行。

    如果一个 try 块后面跟了多个与之关联的 catch 块,那么应该把特定的异常放在前面,通用型的异常放在后面,不然编译器会提示错误。举例来说。

    1. static void test() {
    2. int num1, num2;
    3. try {
    4. num1 = 0;
    5. num2 = 62 / num1;
    6. System.out.println(num2);
    7. System.out.println("try 块的最后一句");
    8. } catch (ArithmeticException e) {
    9. // 算术运算发生时跳转到这里
    10. System.out.println("除数不能为零");
    11. } catch (Exception e) {
    12. System.out.println("异常发生了");
    13. }
    14. System.out.println("try-catch 之外的代码.");
    15. }

    “为什么 Exception 不能放到 ArithmeticException 前面呢?”三妹问。

    “再给你举个例子,注意看,三妹。”

    这段代码在执行的时候,第一个 catch 块会执行,因为除数为零;我再来稍微改动下代码。

    1. try{
    2. int arr[]=new int[7];
    3. arr[9]=30/1;
    4. System.out.println("try 块的最后");
    5. } catch(ArithmeticException e){
    6. System.out.println("除数必须是 0");
    7. } catch(ArrayIndexOutOfBoundsException e){
    8. System.out.println("数组越界了");
    9. } catch(Exception e){
    10. System.out.println("一些其他的异常");
    11. }
    12. System.out.println("try-catch 之外");
    13. }

    “我知道,二哥,第二个 catch 块会执行,因为没有发生算术异常,但数组越界了。”三妹没等我把代码运行起来就说出了答案。

    “三妹,你说得很对,我再来改一下代码。”

    1. static void test1 () {
    2. try{
    3. int arr[]=new int[7];
    4. arr[9]=30/1;
    5. System.out.println("try 块的最后");
    6. } catch(ArithmeticException | ArrayIndexOutOfBoundsException e){
    7. }
    8. }

    “当有多个 catch 的时候,也可以放在一起,用竖划线 | 隔开,就像上面这样。”我说。

    “这样不错呀,看起来更简洁了。”三妹说。

    finally 块的语法也不复杂。

    在没有 try-with-resources 之前,finally 块常用来关闭一些连接资源,比如说 socket、数据库链接、IO 输入输出流等。

    1. OutputStream osf = new FileOutputStream( "filename" );
    2. OutputStream osb = new BufferedOutputStream(opf);
    3. ObjectOutput op = new ObjectOutputStream(osb);
    4. try{
    5. output.writeObject(writableObject);
    6. } finally{
    7. op.close();
    8. }

    “三妹,注意,使用 finally 块的时候需要遵守这些规则。”

    • finally 块前面必须有 try 块,不要把 finally 块单独拉出来使用。编译器也不允许这样做。
    • finally 块不是必选项,有 try 块的时候不一定要有 finally 块。
    • 如果 finally 块中的代码可能会发生异常,也应该使用 try-catch 进行包裹。
    • 即便是 try 块中执行了 return、break、continue 这些跳转语句,finally 块也会被执行。

    “来试一下就知道了。”我说。

    1. static int test2 () {
    2. try {
    3. return 112;
    4. }
    5. finally {
    6. System.out.println("即使 try 块有 return,finally 块也会执行");
    7. }
    8. }

    来看一下输出结果:

    “那,会不会有不执行 finally 的情况呀?”三妹很好奇。

    “有的。”我斩钉截铁地回答。

    • 执行了 System. exit() 这行代码。

    System.exit() 和 语句不同,前者是用来退出程序的,后者只是回到了上一级方法调用。

    “三妹,来看一下源码的文档注释就全明白了!”

    至于参数 status 的值也很好理解,如果是异常退出,设置为非 0 即可,通常用 1 来表示;如果是想正常退出程序,用 0 表示即可。

    “好了,三妹,关于 try-catch-finally 我们就讲到这吧!”我说。

    “没问题,下期见~”