• 20190901 On Java8 第十五章 异常


    第十五章 异常

    要想创建健壮的系统,它的每一个构件都必须是健壮的。

    异常概念

    C++的异常处理机制基于 Ada,Java 中的异常处理则建立在 C++的基础之上(尽管看上去更像 Object Pascal)。

    基本异常

    异常参数

    所有标准异常类都有两个构造器:一个是无参构造器;另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器。

    Throwable 是异常类型的根类。

    自定义异常

    对异常来说,最重要的部分就是类名。

    异常与记录日志

    对于异常类来说,getMessage() 方法有点类似于 toString() 方法。

    异常声明

    不过还是有个能“作弊”的地方:可以声明方法将抛出异常,实际上却不抛出。编译器相信了这个声明,并强制此方法的用户像真的抛出异常那样使用这个方法。这样做的好处是,为异常先占个位子,以后就可以抛出这种异常而不用修改已有的代码。在定义抽象基类和接口时这种能力很重要,这样派生类或接口实现就能够抛出这些预先声明的异常。

    捕获所有异常

    多重捕获

    通过 Java 7 的多重捕获机制,可以将不同类型的异常使用“或”将它们组合起来,只在一个 catch 块中使用:

    try {
        x();
    } catch (Except1 | Except2 | Except3 | Except4 e) {
        process();
    }
    

    栈轨迹

    printStackTrace() 方法所提供的信息可以通过 getStackTrace() 方法来直接访问,这个方法将返回一个由栈轨迹中的元素所构成的数组,其中每一个元素都表示栈中的一桢。元素 0 是栈顶元素,并且是调用序列中的最后一个方法调用(这个 Throwable 被创建和抛出之处)。数组中的最后一个元素和栈底是调用序列中的第一个方法调用。

    重新抛出异常

    只是把当前异常对象重新抛出,那么 printStackTrace() 方法显示的将是原来异常抛出点的调用栈信息,而并非重新抛出点的信息。要想更新这个信息,可以调用 filInStackTrace() 方法,这将返回一个 Throwable 对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的。调用 fillInStackTrace() 的那一行就成了异常的新发生地了。

    精准的重新抛出异常

    Java 7 开始,允许抛出更具体的异常,即 catch 中捕捉的是父类,catch 块中可以抛出子类。

    异常链

    Throwable 的子类中,只有三种基本的异常类提供了带 cause 参数的构造器。它们是 Error(用于 Java 虚拟机报告系统错误)、Exception 以及 RuntimeException。如果要把其他类型的异常链接起来,应该使用 initCause0 方法而不是构造器。

    DynamicFieldsException dfe = new DynamicFieldsException();
    dfe.initCause(new NullPointerException());
    throw dfe;
    

    Java 标准异常

    Throwable 这个 Java 类被用来表示任何可以作为异常被抛出的类。Throwable 对象可分为两种类型(指从 Throwable 继承而得到的类型):Error 用来表示编译时和系统错误(除特殊情况外,一般不用你关心);Exception 是可以被抛出的基本类型,在 Java 类库、用户方法以及运行时故障中都可能抛出 Exception 型异常。所以 Java 程序员关心的基类型通常是 Exception

    异常的基本的概念是用名称代表发生的问题,并且异常的名称应该可以望文知意。异常并非全是在 java.lang 包里定义的;有些异常是用来支持其他像 util、net 和 io 这样的程序包,这些异常可以通过它们的完整名称或者从它们的父类中看出端倪。

    特例:RuntimeException

    RuntimeException 类型的异常(或者任何从 RuntimeException 继承的异常),也被称为“不受检查异常”。这种异常属于错误, 代表的是编程错误,将被自动捕获。

    只能在代码中忽略 RuntimeException(及其子类)类型的异常,因为所有受检查类型异常的处理都是由编译器强制实施的。

    异常限制

    当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。

    异常限制对构造器不起作用。

    一个出现在基类方法的异常说明中的异常,不一定会出现在派生类方法的异常说明里。这点同继承的规则明显不同,在继承中,基类的方法必须出现在派生类里,换句话说,在继承和覆盖的过程中,某个特定方法的“异常说明的接口”不是变大了而是变小了——这恰好和类接口在继承时的情形相反。

    Try-With-Resources 用法

    Java 7 引入了 try-with-resources 语法。

    try-with-resources 定义子句中创建的对象(在括号内)必须实现 java.lang.Autocloseable 接口,这个接口有一个方法,close()。当在 Java 7 中引入 AutoCloseable 时,许多接口和类被修改以实现它;查看 Javadocs 中的 AutoCloseable,可以找到所有实现该接口的类列表,其中包括 Stream 对象。

    规范头中定义的每个对象都会在 try 语句块运行结束之后调用 close() 方法。

    Java 5 中的 Closeable 已经被修改,修改之后的接口继承了 AutoCloseable 接口。所以所有实现了 Closeable 接口的对象,都支持了 try-with-resources 特性。

    不能在资源规范头中定义了一个不是 AutoCloseable 的对象。

    异常匹配

    抛出异常的时候,异常处理系统会按照代码的书写顺序找出“最近”的处理程序。找到匹配的处理程序之后,它就认为异常将得到处理,然后就不再继续查找。

    查找的时候并不要求抛出的异常同处理程序所声明的异常完全匹配。派生类的对象也可以匹配其基类的处理程序。

    其他可选方式

    异常处理的一个重要原则是“只有在你知道如何处理的情况下才捕获异常"。

    所有模型都是错误的,但有些是能用的。

    好的程序设计语言能帮助程序员写出好程序,但无论哪种语言都避免不了程序员用它写出了坏程序。

    异常指南

    应该在下列情况下使用异常:

    1. 尽可能使用 try-with-resource
    2. 在恰当的级别处理问题。(在知道该如何处理的情况下才捕获异常。)
    3. 解决问题并且重新调用产生异常的方法。
    4. 进行少许修补,然后绕过异常发生的地方继续执行。
    5. 用别的数据进行计算,以代替方法预计会返回的值。
    6. 把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。
    7. 把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层。
    8. 终止程序。
    9. 进行简化。(如果你的异常模式使问题变得太复杂,那用起来会非常痛苦也很烦人。)
    10. 让类库和程序更安全。(这既是在为调试做短期投资,也是在为程序的健壮性做长期投资。)
  • 相关阅读:
    双循环建表____1911年 为 辛亥年
    技巧方法
    sscanf
    02-02环境准备-pyenv与virtualenv以及venv方案对比
    02-01环境准备-virtualenv和venv
    02-01环境准备-pyenv
    【转】解决weblogic启动慢和创建域慢的方法
    chrome新版打开新标签页自动打开谷歌主页
    centos6分辨率设置
    12-openldap使用AD密码
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/11442034.html
Copyright © 2020-2023  润新知