问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

异常概述及其抛出与捕获机制

创作时间:
作者:
@小白创作中心

异常概述及其抛出与捕获机制

引用
CSDN
1.
https://m.blog.csdn.net/weixin_44814196/article/details/140832882

一、异常概述

1.1 什么是异常

异常(exception)是在程序执行期间发生的事件,它会破坏程序指令的正常流程。exception 是 exceptional event 的缩写

当方法中发生错误时,该方法创建一个对象并将其交给运行时系统。该对象称为异常对象(exception object),包含有关错误的信息,包括其类型和错误发生时程序的状态。创建异常对象并将其交给运行时系统称为抛出异常(throw exception)

1.2 引入异常的好处

引入异常处理机制为程序设计提供了许多好处,以下是主要的一些好处:

  • 将错误处理代码与常规代码分开
  • 在调用堆栈中传播错误
  • 分组并区分错误类型

1.3 异常处理流程

在一个方法抛出异常后,运行时系统试图在调用堆栈中搜索包含可以处理异常的代码块的方法。该代码块称为异常处理程序(exception handler)

搜索从发生错误的方法开始,并以调用方法的相反顺序继续通过调用栈。当找到合适的处理程序时,运行时系统将异常传递给处理程序。如果抛出的异常对象的类型与处理程序可以处理的类型匹配,则认为异常处理程序是合适的。

简单来说,异常处理的逻辑遵循调用链,即从方法的调用者向上传递

1.4 异常处理机制的要求

异常通常分为已检查异常(Checked Exceptions)、未检查异常(Unchecked Exceptions)、错误(Errors)。其中,抛出已检查异常的代码必须满足以下两种情况之一

  • 捕获异常(Catch the Exception):使用
    try
    语句捕获异常。
    try
    语句必须提供异常处理程序,即包含
    catch
    块,用于处理可能抛出的异常。
try {
    // 可能抛出异常的代码
} catch (SomeException e) {
    // 异常处理代码
}
  • 指定异常(Specify the Exception):方法声明中指定它可能抛出异常。方法必须提供
    throws
    子句,列出可能抛出的异常。
public void someMethod() throws SomeException {
    // 可能抛出异常的代码
}

如果代码不满足上述要求,将无法编译通过。

二、异常类型

2.1 异常类别

异常分为三大类:

  • 已检查异常(Checked Exceptions)

  • 这些异常是编译时异常,必须要么被捕获要么被声明。编译器在在编译阶段会进行检查。

  • 这些是编写良好的应用程序应该预见并从中恢复的异常条件。

  • 例如:
    FileNotFoundException

    IOException
    ,
    SQLException

  • 未检查异常(Unchecked Exceptions)

  • 这些异常是运行时异常,继承自
    RuntimeException
    。未检查异常存在争议

  • 这些异常是应用程序内部的异常情况,应用程序通常无法预测或恢复。这些通常表明编程错误,如逻辑错误或 API 使用不当。

  • 例如:
    NullPointerException
    ,
    ArrayIndexOutOfBoundsException

  • 错误(Errors)

  • 这些是由 JVM 引发的严重错误,继承自
    Error

  • 这些是应用程序外部的异常情况,应用程序通常无法预测或从中恢复。

  • 例如:
    OutOfMemoryError
    ,
    StackOverflowError

其中,未检查异常(Unchecked Exceptions) 和错误(Errors)不需要遵循捕获或指定异常的要求。也就是说,针对这两种异常,我们可以不用编写异常处理程序进行处理。

注意:编译时异常是指编译器在编译阶段进行检查的异常类型,但这些异常实际上是在程序运行时可能会发生的。例如,
FileNotFoundException
是编译时异常,如果指定的文件在运行时不存在,则会抛出这个异常。

2.2 Exception 类的层次

Throwable
类的直接后代有:

  • Error: 错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
  • Exception:所有的异常类都是 java.lang.Exception 类的子类。

三、抛出异常

3.1 throws 关键字

throws 关键字是 Java 中用于方法声明的一部分,它指明了该方法可能会抛出某些类型的已检查异常。可以这样理解,方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误

public void readFile(String fileName) throws FileNotFoundException {
    // 方法实现
}

3.2 throw 关键字

throw 关键字可以在代码中抛出一个异常对象。当一个方法使用 throw 抛出异常时,程序控制权会转移到该方法的调用者。调用者需要有适当的 try-catch 结构来捕获并处理该异常。

throw 语句需要一个参数:一个可抛出对象。可抛出对象是 Throwable 类的任何子类的实例。

throw someThrowableObject;

示例如下:

public void validate(int value) {
    if (value < 0) {
        throw new IllegalArgumentException("Negative value not allowed.");
    }
}

3.3 链式异常

应用程序通常通过抛出另一个异常来响应已发生的异常。换句话说,第一个异常可能会导致第二个异常的产生。了解何时一个异常会导致另一个异常是非常重要的,这种机制被称为链式异常(Chained Exception),它有助于程序员追踪异常的源头和原因。

Throwable
常见的支持链式异常的方法如下:

Throwable getCause()
Throwable initCause(Throwable)
Throwable(String, Throwable)
Throwable(Throwable)

示例如下:

try {
} catch (IOException e) {
    throw new SampleException("Other IOException", e);
}

这段代码展示了如何在捕获 IOException 异常后,创建一个新的自定义异常 SampleException,并附加原始原因。然后,将异常链抛出到下一个更高级别的异常处理程序。

3.4 throw 和 throws 的区别

当你在方法中使用 throw 抛出异常时,这表示在特定条件下发生了某种错误。使用 throws 声明异常时,你是在声明这个方法可能会引发错误,以便调用这个方法的代码能做好相应的异常处理。

throw 和 throws 的区别在于:

特性 throw throws
作用 抛出一个异常实例 声明方法可能抛出的异常类型
使用位置 方法内部 方法签名(声明部分)
语法格式 throw new ExceptionType() void methodName() throws ExceptionType
强制要求 不强制要求捕获 调用方法时必须捕获或继续声明异常

四、捕获异常(异常处理程序)

在抛出异常后,运行时系统会在调用堆栈中找到异常处理程序来处理该异常。

另外,异常处理程序里面可以在 catch 块里面再次抛出异常与链式异常。通常,希望改变异常的类型时才会这样做。

4.1 try-catch-finally

异常处理程序主要是由异常处理程序组件 try、catch 、finally 来实现。其中:

  • try:用于捕获异常。try 块不能单独存在,后面至少跟着一个 catch块 或者 一个 finally 块,也可以跟着多个 catch 块。
  • catch:处理异常,被称为异常处理程序。另外,单个catch 块可以处理多种类型的异常,不同类型的异常用
    |
    分割
  • finally:用于在异常处理结束后执行清理工作,无论是否抛出异常。当在
    try
    块或
    catch
    块中遇到
    return
    语句时,
    finally
    语句块将在方法返回之前被执行。注意,当 JVM 退出时,finally 块可能不会执行
try {
    // 初始化资源或执行可能抛出异常的操作
    resource = initializeResource()
        // 执行主要操作
        performMainTask(resource)
} catch (SpecificExceptionType1 exception1) {
    // 处理特定类型的异常1
    handleExceptionType1(exception1)
} catch (SpecificExceptionType2 exception2) {
    // 处理特定类型的异常2
    handleExceptionType2(exception2)
} catch (GeneralException exception) {
    // 处理其他一般性异常
    handleGeneralException(exception)
} finally {
    // 清理资源或执行无论如何都会执行的操作
    if (resource is not null) {
        resource.close()
    }
}

4.2 try-with-resources

try-with-resource语法结构,旨在自动管理资源,确保资源在使用后能够及时关闭,避免资源泄露 。无论代码块中的操作是否成功,资源都会在 try 代码块执行完毕后自动关闭。。

try-with-resources 语句特别适合使用 Closeable 资源的情况,例如流。

try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    // 读取文件的代码
} catch (IOException e) {
    // 处理异常
}

参考资料

  • Exceptions - Dev.java
  • Java 异常处理 | 菜鸟教程 (runoob.com)
  • Java基础常见面试题总结(下) | JavaGuide
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号