• Java中的异常处理机制


    聊聊Java中的异常处理机制

    概念

    异常处理

    在Java中,处理异常的语句由try、catch、finally三部分组成。其中,try块用于包裹业务代码,catch块用于捕获并处理某个类型的异常,finally块则用于回收资源。当业务代码发生异常时,系统会创建一个异常对象,然后由JVM寻找可以处理这个异常的catch块,并将异常对象交给这个catch块处理。若业务代码打开了某项资源,则可以在fifinally块中关闭这项资源,因为无论是否发生异常,finally块一定会执行。

    抛出异常

    关于抛出异常:

    当程序出现错误时,系统会自动抛出异常。除此以外,Java也允许程序主动抛出异常。当业务代码中,判断某项错误的条件成立时,可以使用throw关键字向外抛出异常。在这种情况下,如果当前方法不知道该如何处理这个异常,可以在方法签名上通过throws关键字声明抛出异常,则该异常将交给JVM处理。

    异常跟踪栈:

    程序运行时,经常会发生一系列方法调用,从而形成方法调用栈。异常机制会导致异常在这些方法之间传播,而异常传播的顺序与方法的调用相反。异常从发生异常的方法向外传播,首先传给该方法的调用者,再传给上层调用者,以此类推。最终会传到main方法,若依然没有得到处理,则JVM会终止程序,并打印异常跟踪栈的信息

    异常处理步骤:

    处理异常步骤如下所示:

    1. 捕获异常

    将业务代码包裹在try块内部,当业务代码中发生任何异常时,系统都会为此异常创建一个异常对象。创建异常对象之后,JVM会在try块之后寻找可以处理它的catch块,并将异常对象交给这个catch块处理。

    2. 处理异常

    在catch块中处理异常时,应该先记录日志,便于以后追溯这个异常。然后根据异常的类型、结合当前的业务情况,进行相应的处理。比如,给变量赋予一个默认值、直接返回空值、向外抛出一个新的业务异常交给调用者处理,等等。

    3. 回收资源

    如果业务代码打开了某个资源,比如数据库连接、网络连接、磁盘文件等,则需要在这段业务代码执行完毕后关闭这项资源。并且,无论是否发生异常,都要尝试关闭这项资源。将关闭资源的代码写在finally块内,可以满足这种需求,即无论是否发生异常,finally块内的代码总会被执行。

    Java的异常处理接口

    Java中,Throwable是异常的顶层父类,代表所有的非正常情况。它有两个直接子类,分别是Error、Exception。

    • Error是错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该试图使用catch块来捕获Error对象。在定义方法时,也无须在其throws子句中声明该方法可能抛出Error及其任何子类。

    • Exception是异常,它被分为两大类,分别是Checked异常和Runtime异常。所有的RuntimeException类及其子类的实例被称为Runtime异常;不是RuntimeException类及其子类的异常实例则被称为Checked异常。Java认为Checked异常都是可以被处理(修复)的异常,所以Java程序必须显式处理Checked异常。如果程序没有处理Checked异常,该程序在编译时就会发生错误,无法通过编译。Runtime异常则更加灵活,Runtime异常无须显式声明抛出,如果程序需要捕获Runtime异常,也可以使用try…catch块来实现。

    关于 finally

    finally是无条件执行的吗?

    不管try块中的代码是否出现异常,也不管哪一个catch块被执行,甚至在try块或catch块中执行了return语句,finally块总会被执行。

    注意事项

    如果在try块或catch块中使用 System.exit(1); 来退出虚拟机,则finally块将失去执行的机会。但是我们在实际的开发中,从来都不会这样做,所以尽管存在这种导致finally块无法执行的可能,也只是一种可能而已。

    比如下面代码:

    package com.yyl.exception;
    
    public class ExceptionTest {
        public static void main(String[] args) {
            try {
                System.exit(1);
            }catch (Exception e){
                System.out.println(e);
            }finally {
                System.out.println("finally");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    结果啥也没有:

    image-20220815101054336

    在finally中return会发生什么?

    在通常情况下,不要在finally块中使用return、throw等导致方法终止的语句,一旦在finally块中使用了return、throw语句,将会导致try块、catch块中的return、throw语句失效

    详细解析

    当Java程序执行try块、catch块时遇到了return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块:

    • 如果没有finally块,程序立即执行return或throw语句,方法终止;

    • 如果有finally块,系统立即开始执行finally块。只有当finally块执行完成后,系统才会再次跳回来执行try块、catch块里的return或throw语句;

    如果finally块里也使用了return或throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去执行try块、catch块里的任何代码。

    测试代码如下:

    package com.yyl.exception;
    
    public class ExceptionTest {
        public static void main(String[] args) {
            System.out.println(returnFinally());
        }
    
        public static String returnFinally(){
            try {
               int i=1;
               return "try";
            }catch (Exception e){
                System.out.println(e);
                return "catch";
            }finally {
                System.out.println("执行finally");
                return "finally";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    最后返回的是finally:

    image-20220815101450454

    发生异常也是这样的:

    package com.yyl.exception;
    
    public class ExceptionTest {
        public static void main(String[] args) {
            System.out.println(returnFinally());
        }
    
        public static String returnFinally(){
            try {
               // 制造个除0异常
               int i=1/0;
               return "try";
            }catch (Exception e){
                System.out.println(e);
                return "catch";
            }finally {
                System.out.println("执行finally");
                return "finally";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    image-20220815101545736

    当然要是不在finally写return,没有异常就返回try中的return,有异常就返回catch中的return

    • 无异常

    image-20220815101611549

    • 有异常

    image-20220815101559849

  • 相关阅读:
    软件项目管理 6.3.用例点估算法
    一文彻底理解逻辑回归:从公式推导到代码实现
    直播预告|一键观看关联网络与团伙欺诈的爱恨情仇
    Maven(项目构建管理工具)
    Anaconda下的pkgs占用空间13G,如何安全的清理(已解决)
    DTFT和DFT有何区别?一文为你讲解清楚
    图神经网络 图像处理,神经网络与图像处理
    第六篇Android--ImageView、Bitmap
    uni-app 5小时快速入门 3 创建uni-app工程(下)
    Spring系列七:JDK 动态代理和 CGLIB 代理
  • 原文地址:https://blog.csdn.net/weixin_45525272/article/details/126341786