美文网首页
第十章 异常处理

第十章 异常处理

作者: Utte | 来源:发表于2017-08-06 04:04 被阅读27次

    异常概述

    • 依赖于try catch finally throw throws五个关键字
    • Java把一场分为两种:Checked Runtime,Checked异常可以在编译阶段被发现,所以强制程序处理所有的Checked异常,Runtime异常无需处理
    • 无法穷举所有的异常情况,错误处理代码和业务实现代码混杂,影响可读性,增加维护难度,使用Java异常处理机制就可以解决这个问题
    • Java把错误分为Exception和Error,Error一般指与虚拟机相关的问题,通常程序无法处理这些错误,所以不应该使用catch捕捉Error对象

    异常处理机制

    使用try...catch捕获异常

    try
    {
    //业务实现代码
    }
    catch (Excption e)
    {
    //处理异常
    }
    
    • 当try中业务逻辑代码出现异常时,系统会自动生成一个异常对象交给Java运行时环境,抛出(throw)异常

    • 抛出异常后,Java运行时环境收到异常对象时寻找对应的catch块交给其处理,如果找不到捕获异常的catch块,则运行时环境种植,程序退出

    • 会依次判断该异常对象是否为catch块后异常类或其子类的实例,如果是则交由其处理

    • try块后的花括号不能省略,catch也不能省略

    • catch应该先处理小异常再处理大异常,把父类异常的catch块排在子类的后面,否则会出现编译错误

    • Java7提供多异常捕获,一个catch可以捕获多种类型的异常,用|隔开,捕获多种类型的异常时,异常变量有隐式的final修饰,程序不能对其重新赋值catch (...|...|... e){}

    • 异常对象包含的访问信息的方法:getMessage printStackTrace getStackTrance

    finally回收资源

    • try块内打开的物理资源(数据库连接、网络连接、磁盘文件等),这些物理资源必须显式回收
    try{}
    catch(.. e){}
    catch(.. e){}
    ...
    finally
    {
    //回收资源
    }
    
    • 只有try块时必须的,catch和finally至少出现其中之一,finally位于catch之后,catch位于try之后
    • 除非再try或catch中调用了退出虚拟机的方法System.exit(1);,不管怎么样finally块总会被执行
    • 通常不要在finally块中使用return或throw方法终止语句,会导致try catch中的return throw语句失效
    • 层次太深的潜逃异常处理没有太大的必要,会导致程序可读性降低
    • Java7自动给关闭资源的try语句,资源的实现类必须实现AutoCloseable或Closeable(AutoCloseable子接口,只能抛出IOException或其子类)接口,也就是实现了close()方法try(//声明初始可关闭的资源){}
    • 自动关闭资源的try语句相当于包含了隐式的finally块,所以这个try可以既没有catch块也没有finally块

    Checked和Runtime异常体系

    • 不是RuntimeException类及其子类的异常实例称为Checked异常
    • 对于Checked异常的处理方式
      • 当明确知道如何处理时使用try...catch捕获修复该异常
      • 当前方法不知道如何处理时应该在定义该方法时抛出该异常
    • Runtime异常无需显式声明抛出,如果需要捕获,也可以使用try...catch
    • throws声明抛出异常,throws EC1,EC2...
      public static void main(String[] args) throws IOException {}
    • 当前方法不知如何处理该异常,则抛出有上一级调用者处理,如果main方法也不知道,也可以使用throws抛出交给JVM处理。
    • JVM处理异常:打印异常跟踪栈信息,终止程序运行。
    • 重写使用throws声明抛出异常的方法时,子类方法声明抛出的异常类型应该时父类的相同类或子类,并且子类方法声明抛出的异常不能比父类声明的多

    throw抛出异常

    • Java允许自行抛出异常,使用throw语句throw ExceptionInstance;
    • 如果抛出Checked异常,需要处于try块或有throws声明抛出的方法中,如果是Runtime异常,则不需要,自行抛出Runtime异常比Checked异常灵活

    自定义异常类

    • 需要继承Exception基类,如果自定义Runtime异常则可以继承RuntimeException基类
    • 通常需要两个构造器,一个无参,一个字符串参数(描述异常对象的信息),getMessage()返回值public myException(String msg){super(msg);}

    catch和throw同时使用

    • 在出现异常的方法内捕获并处理异常,该方法的调用者将不能再次捕获该异常
    • 方法签名中声明抛出该异常,改异常将完全交给方法的调用者处理
    • 在实际应用中,完全处理一个异常必须由几方法写作才可以,比如在出现异常的方法中捕获并处理部分,还需要再次抛出,让调用者也捕获到异常处理剩下的部分
    • 在catch块中结合throw语句完成
    catch (Exception e)
    {
        e.printStackTrace();//在本方法中只是进行一个打印异常信息的操作
        throw new AuctionException("想传递的信息");//再次抛出自定义异常
    }
    
    • 企业级应用对异常处理通常分为两部分
      • 应用后台需要通过日志记录异常发生的详细情况
      • 向应用的使用者传达提示
    • Java7增强的throw语句,编译器会检查throw语句抛出异常的实际类型,而不是仅根据catch后的类型判断,因此方法声明中只需要声明抛出实际类型的异常即可

    异常链

    • 不应该把底层的异常传到用户界面,对于用户,此举没有任何帮助,且对于恶意用户,暴露异常是不安全的
    • 应该把底层原始异常捕获,抛出一个新的业务异常,这种处理方式叫做异常转译,完全符合面向对象的封装原则
    • 捕获一个异常接着抛出另一个异常,并把原始已异常信息保存下来是一种典型的链式处理,职责链模式,也称为异常链
    • Java1.4后Throwable的子类在构造器中可以接受一个cause对象作为参数,表示原始异常,这样可以通过异常链追踪到异常最初发生的位置,获取原始异常信息

    异常跟踪栈

    • 只要异常没有被完全捕获,从发生异常的方法逐渐向外传播,打印异常的跟踪栈信息
    • printStackTrace()方法用于调试,最终还是应该避免使用它,应该对捕获的异常进行处理,而不是简单的打印

    异常处理规则

    • 成功处理异常的四个目标
      • 是程序代码混乱最小化
      • 捕获并保留诊断信息
      • 通知合适的人员
      • 采用合适的方式结束异常活动
    • 异常只应该用于处理非正常的情况,不要去代替正常的流程控制
    • 不要使用过于庞大的try块,应该分割成单独的try块,分别捕获并处理异常
    • 避免使用Catch All语句,catch(Throwable t){...}
    • 不要忽略捕获到的异常,去处理异常,重新抛出新异常,再在合适的层处理异常

    相关文章

      网友评论

          本文标题:第十章 异常处理

          本文链接:https://www.haomeiwen.com/subject/pkhglxtx.html