首页 > 编程笔记

Java异常处理机制详解

异常(Exception)是在程序执行期间发生的特殊事件。一般来说,异常会中断正在执行的程序的正常指令流。

在程序中,异常可能产生于开发者没有预料到的各种情况,或者超出开发者的可控范围,如除数为 0、数组下标越界、试图打开一个不存在的文件等。为了能够及时有效地处理程序中的运行异常,Java 专门引入了异常机制。

异常机制(Exception Handling)是在程序执行期间对异常的发生做出响应的过程。Java 中存在两种主要的指令流,一种是正常指令流,另一种是异常处理指令流。当程序在运行过程中出现意外情况时,系统会自动生成一个异常对象来通知程序。此时,正常的程序控制流程停止运行并开始搜索匹配的异常处理逻辑块(catch 语句块)。当找到一个匹配的 catch 语句块时,将执行该块,异常对象作为参数传递给该块,并在执行 catch 语句块之后继续正常地执行程序。

若在当前方法级别中没有找到 catch 语句块,则在调用者方法级别中继续搜索,直到找到匹配的 catch 语句块。若最终没有发现相匹配的 catch 语句块,则将异常交由 Java 虚拟机处理,通常会终止当前线程,进而可能终止整个 Java 程序。

开发者可以通过提供异常处理逻辑块,在 Java 程序中预置各类潜在异常的处理方案,提升所开发的 Java 程序的健壮性。同时,开发者可以基于 Java 异常机制构建统一的错误报告模型,记录程序运行过程中产生的异常信息,为异常排查和异常修复提供依据,提高异常修复效率。

Java的异常的分类

在 Java 中,所有异常类型都是内置类 java.lang.Throwable 的子类,即 Throwable 是所有异常和错误的超类。

Throwable 位于异常类层次结构的顶层,下面的两个异常分支 Exception 和 Error 分别表示异常和错误,如下图所示。


图 1 Java的异常的分类

Exception 代表可控的异常,一般是程序编码错误或外在因素导致的、可以被开发者预见并提供异常解决方案的各类问题。这些问题能够被系统捕获并处理,从而避免应用程序非正常中断,如对负数开平方根、除数为 0 等。

常见的异常类如下表所示。

表:常见的异常类
异常类 说 明
NullPointerException 空指针异常
ClassCastException 类型转换异常
ArraylndexOutOfBoundsException 数组越界异常
ArithmeticException 算术异常
InternalException Java 系统内部异常
lOException 在一般情况下不能完成输入/输出操作时所产生的异常
EOFException 打开文件没有数据可以读取时所产生的异常
FileNotFoundException 在文件系统中找不到文件名称或路径时所产生的异常
 
ClassNotFoundException 找不到类或接口时所产生的异常
IllegalAccessException 类定义不明确时所产生的异常
NegativeArraySizeException 指定数组维数为负值时所产生的异常
NumberFormatException 数字格式化时所产生的异常

Error 类定义了在通常环境下不希望被程序捕获的问题,通常是与虚拟机相关的问题,如虚拟机错误、堆栈溢出和系统崩溃等,这些错误系统无法捕获并处理。对于这些错误开发者无能为力,将导致应用程序中断。

Java 中的 Exception 类可以进一步细分为运行时异常(也称为非受检异常)和编译时异常(也称为抽检异常)。

运行时异常都是 RuntimeException 类及其子类异常,如 NullPointerException、IndexOutOfBoundsException 等。此类异常是非受检异常,即编译器不会检查开发者是否为可能出现的异常提供了处理逻辑。程序可以选择捕获处理,也可以不处理。此类异常一般是由程序逻辑错误引起的,开发者应该从逻辑角度尽可能避免这类异常的发生。

编译时异常是指 RuntimeException 以外的异常,属于 Exception 类及其子类异常。从程序语法角度讲必须处理的异常如果不处理,程序就不能编译通过,如 IOException、ClassNotFoundException,以及用户自定义的 Exception 异常等。

异常的常用方法

java.lang.Throwable 是所有 Exception 类和 Error 类的父类,其中声明的方法被所有 Exception 类继承。Throwable 类中声明的常用的方法有 getMessage()、getLocalizedMessage()、getCause()和printStackTrace(),下面介绍这些方法:
接下来通过实例来介绍异常类的常用方法。

【实例】异常类的常用方法。
public class Test {
    public static void main(String[] args) {
        // 新建异常对象,传入自定义的消息
        RuntimeException el = new RuntimeException("el 的自定义异常原因");
        System.out.println("------el.getMessage()-----");
        System.out.println(el.getMessage());
        System.out.println("------el.getCause()-----\n");
        // 当无其他异常导致该异常时,返回null
        System.out.println(el.getCause());
        System.out.println("------el.printStackTrace()-----\n");
        // 该方法中包含对打印方法的调用,信息中包含方法调用轨迹
        // 该方法默认使用 System.err 打印信息
        // 本实例指定使用 System.out 打印信息
        el.printStackTrace(System.out);
        // 创建一个新的异常对象,设置由el导致了该异常
        RuntimeException e2 = new RuntimeException("e2 的自定义异常原因", el);
        System.out.println("-----e2.getCause()-----");
        // 返回el的信息
        System.out.println(e2.getCause());
        System.out.println("-----e2.printStackTrace()-----");
        // 信息中会使用"Caused by:"显示导致当前异常的底层异常信息
        e2.printStackTrace(System.out);
    }
}
运行结果为:

------el.getMessage()-----
el 的自定义异常原因
------el.getCause-----
null
------el.printStackTrace()-----
java.lang.RuntimeException: el 的自定义异常原因
-----e2.getCause()-----
java.lang.RuntimeException: el 的自定义异常原因
-----e2.printStackTrace()-----
java.lang.RuntimeException: e2 的自定义异常原因
Caused by: java.lang.RuntimeException: el 的自定义异常原因
    at Test.main(Test.java:23)

推荐阅读

副业交流群 关注微信公众号,加入副业交流群,学习变现经验,交流各种打法。