Java 异常:深入理解与实践

在 Java 编程中,异常处理是一个至关重要的部分,它能够帮助我们构建更加健壮和稳定的应用程序。本文将深入探讨 Java 异常的相关知识,包括异常类层次结构、不同类型异常的区别、常用方法以及异常处理的方式等。

一、异常类层次结构

在 Java 中,所有的异常都有一个共同的祖先 ——java.lang包中的Throwable类。Throwable类有两个重要的子类:ExceptionError

(一)Exception

Exception表示程序本身可以处理的异常,可以通过catch来进行捕获。它又可以进一步分为Checked Exception(受检查异常,必须处理)和Unchecked Exception(不受检查异常,可以不处理)。

(二)Error

Error属于程序无法处理的错误,我们没办法通过catch来进行捕获,也不建议这样做。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等。当这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

二、Checked Exception 和 Unchecked Exception 的区别

(一)Checked Exception

即受检查异常,Java 代码在编译过程中,如果受检查异常没有被catch或者throws关键字处理的话,就没办法通过编译。例如 IO 操作相关的代码,如果文件不存在引发FileNotFoundException,就必须进行处理。除了RuntimeException及其子类以外,其他的Exception类及其子类都属于受检查异常。常见的受检查异常有:IO 相关的异常、ClassNotFoundExceptionSQLException等。

(二)Unchecked Exception

即不受检查异常,Java 代码在编译过程中,即使不处理不受检查异常也可以正常通过编译。RuntimeException及其子类都统称为非受检查异常,常见的有:NullPointerException(空指针错误)、IllegalArgumentException(参数错误比如方法入参类型错误)、NumberFormatException(字符串转换为数字格式错误,IllegalArgumentException的子类)、ArrayIndexOutOfBoundsException(数组越界错误)、ClassCastException(类型转换错误)、ArithmeticException(算术错误)、SecurityException(安全错误比如权限不够)、UnsupportedOperationException(不支持的操作错误比如重复创建同一用户)等。

三、Throwable 类常用方法

  1. String getMessage():返回异常发生时的简要描述。
  2. String toString():返回异常发生时的详细信息。
  3. String getLocalizedMessage():返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同。
  4. void printStackTrace():在控制台上打印Throwable对象封装的异常信息。

四、try - catch - finally 的使用

(一)try 块

用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。

(二)catch 块

用于处理try捕获到的异常。

(三)finally 块

无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。需要注意的是,不要在finally语句块中使用return,当try语句和finally语句中都有return语句时,try语句块中的return语句会被忽略。

以下是一个简单的代码示例:

try {
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
    System.out.println("Catch Exception -> " + e.getMessage());
} finally {
    System.out.println("Finally");
}

输出结果为:

Try to do something
Catch Exception -> RuntimeException
Finally

不过,在某些特殊情况下,finally中的代码不会被执行,比如在finally之前虚拟机被终止运行,或者程序所在的线程死亡,以及关闭 CPU 等情况。

五、try - with - resources

适用范围为任何实现java.lang.AutoCloseable或者java.io.Closeable的对象。在try - with - resources语句中,任何catchfinally块在声明的资源关闭后运行。相比于try - catch - finally,它能让代码更简短、更清晰,产生的异常也更有用。例如读取文件内容的操作,使用try - with - resources可以简化代码:

try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

六、异常使用的注意事项

  1. 不要把异常定义为静态变量,因为这样会导致异常栈信息错乱。每次手动抛出异常,都需要手动new一个异常对象抛出。
  2. 抛出的异常信息一定要有意义。
  3. 建议抛出更加具体的异常,比如字符串转换为数字格式错误的时候应该抛出NumberFormatException而不是其父类IllegalArgumentException
  4. 避免重复记录日志,如果在捕获异常的地方已经记录了足够的信息(包括异常类型、错误信息和堆栈跟踪等),那么在业务代码中再次抛出这个的异常时,就不应该再次记录相同的错误信息。重复记录日志会使得日志文件膨胀,并且可能会掩盖问题的实际原因,使得问题更难以追踪和解决。

通过对 Java 异常的深入理解和正确使用,我们能够更好地处理程序运行过程中可能出现的各种问题,提高程序的可靠性和稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值