Java异常处理全解析
立即解锁
发布时间: 2025-08-18 01:55:06 阅读量: 2 订阅数: 5 

### Java 异常处理全解析
#### 1. 异常概述
在 Java 编程中,异常是一种用于在程序执行过程中发出严重问题信号的机制。标准类广泛使用异常。异常通常在程序出现错误时抛出,而且如果代码中存在出错的可能性,那么迟早会出错,因此在设计和编写程序时,异常处理是一个非常基本的考虑因素。
异常并不总是意味着错误,它也可以表示程序中需要特别关注的异常事件。使用异常来发出错误信号的一个主要好处是,它将处理错误的代码与正常执行的代码分离开来。此外,异常还提供了一种强制对特定错误做出响应的方式,对于许多类型的异常,程序中必须包含处理它们的代码,否则代码将无法编译。
不过,并非所有的错误都需要通过异常来发出信号。异常应该用于处理可能出现的异常或灾难性情况,例如用户输入错误通常是正常事件,应该在不使用异常的情况下处理,因为处理异常会带来大量的处理开销,如果程序经常处理异常,会导致运行速度变慢。
Java 中的异常是一个对象,当程序中出现异常情况时会创建该对象。异常对象包含有关问题性质的信息。异常被抛出时,标识异常情况的对象会作为参数传递给专门处理该问题的代码块,接收异常对象作为参数的代码块称为捕获异常。
异常产生的情况多种多样,但大致可分为以下四类:
| 异常类型 | 描述 | 示例 |
| ---- | ---- | ---- |
| 代码或数据错误 | 例如对象的无效类型转换、使用超出数组范围的索引或整数算术表达式中的除数为零 | 尝试将整数除以零、使用超出数组边界的索引 |
| 标准方法异常 | 标准类中的方法可能抛出的异常 | `String` 类的 `substring()` 方法可能抛出 `StringIndexOutOfBoundsException` 异常 |
| 自定义异常 | 程序员根据需要自己抛出的异常 | - |
| Java 错误 | 可能由于 Java 虚拟机执行错误或程序本身的错误导致 | - |
#### 2. 异常类型
所有异常都是标准类 `Throwable` 的子类对象,包括自定义异常和标准异常。`Throwable` 有两个直接子类:`Error` 和 `Exception`,它们涵盖了所有标准异常,并且这两个类本身还有子类用于标识特定的异常条件。
- **Error 异常**:`Error` 类及其子类定义的异常表示程序无法处理的情况,通常不需要捕获。`Error` 有三个直接子类:
- `ThreadDeath`:当执行线程被故意停止时抛出该异常,为了正确销毁线程,通常不应该捕获它。在某些情况下,可能需要捕获它进行清理操作,但之后必须重新抛出异常,以允许线程正常结束。
- `LinkageError`:该异常类的子类记录程序中类的严重错误,例如类之间的不兼容或尝试创建不存在的类类型的对象。
- `VirtualMachineError`:该类有四个子类,用于指定 Java 虚拟机发生灾难性故障时抛出的异常。通常,捕获这些异常没有太大意义。
- **RuntimeException 异常**:`Exception` 类的大多数子类要求程序中包含处理它们的代码,否则代码无法编译。但 `RuntimeException` 及其子类是例外,编译器允许忽略这些异常,因为它们通常是由代码中的严重错误引起的,在大多数情况下难以恢复。`java.lang` 包中定义的 `RuntimeException` 子类包括:
| 类名 | 异常条件 |
| ---- | ---- |
| `ArithmeticException` | 无效的算术条件,例如整数除以零 |
| `IndexOutOfBoundsException` | 尝试使用超出对象范围的索引,可能是数组、`String` 对象或 `Vector` 对象 |
| `NegativeArraySizeException` | 尝试定义具有负维度的数组 |
| `NullPointerException` | 使用包含 `null` 的对象变量,而该变量应该引用一个对象 |
| `ArrayStoreException` | 尝试将对象存储在不允许的数组类型中 |
| `ClassCastException` | 尝试将对象强制转换为无效类型 |
| `IllegalArgumentException` | 传递给方法的参数与参数类型不匹配 |
| `SecurityException` | 程序执行了违反安全规则的非法操作 |
| `IllegalMonitorStateException` | 线程尝试等待它不拥有的对象的监视器 |
| `IllegalStateException` | 在不合法的时间调用方法 |
| `UnsupportedOperationException` | 请求执行不支持的操作 |
- **其他 `Exception` 子类**:除了 `RuntimeException` 及其子类外,`Exception` 类的其他子类要求编译器检查是否在可能抛出异常的方法中处理了该异常,或者是否在方法定义中声明了可能抛出该异常。
#### 3. 处理异常
当代码可能抛出除 `Error` 或 `RuntimeException` 类型之外的异常时,必须采取相应的措施。处理异常有两种选择:在方法内部提供处理异常的代码,或者将异常传递给调用该方法的代码。
##### 3.1 指定方法可能抛出的异常
如果方法可能抛出既不是 `RuntimeException` 也不是 `Error` 子类的异常,例如 `IOException`,则必须在方法定义中声明该异常。可以通过在方法定义中添加 `throws` 子句来实现,例如:
```java
double myMethod() throws IOException, FileNotFoundException {
// 方法代码细节...
}
```
如果另一个方法调用了这个可能抛出异常的方法,它也必须考虑处理这些异常,要么在方法内部处理,要么声明该方法可能抛出这些异常。
##### 3.2 处理异常的代码块
可以在方法中使用三种类型的代码块来处理异常:`try`、`catch` 和 `finally` 块。
- **try 块**:当需要捕获异常时,可能抛出异常的代码必须包含在 `try` 块中。如果代码不在 `try` 块中,包含该代码的方法将无法捕获抛出的异常,并且必须声明可能抛出的异常类型。`try` 块的语法如下:
```java
try {
// 可能抛出一个或多个异常的代码
}
```
- **catch 块**:用于处理特定类型的异常,必须紧跟在包含可能抛出该异常代码的 `try` 块之后。`catch` 块的语法如下:
```java
try {
// 可能抛出异常的代码
} catch(ArithmeticException e) {
// 处理异常的代码
}
```
`catch` 块的参数必须是 `Throwable` 或其子类类型。如果指定的参数类型有子类,`catch` 块将处理该类及其所有子类的异常。
当 `try` 块可能抛出多种不同类型的异常时,可以使用多个 `catch` 块来处理它们。多个 `catch` 块的顺序很重要,必须按照从最具体的子类到最基本的父类的顺序排列,否则代码将无法编译。
以下是一个使用 `try` 和 `catch` 块的示例:
```java
public class TestTryCatch {
public static void main(String[] args) {
int i = 1;
int j = 0;
try {
System.out.println("Try block entered " + "i = " + i + " j = " + j);
System.out.println(i/j); // 除以 0 - 抛出异常
System.out.println("Ending try block");
} catch(ArithmeticException e) { // 捕获异常
System.out.println("Arithmetic exception caught");
}
System.out.println("After try block");
return;
}
}
```
运行该示例,输出结果如下:
```
Try block entered i = 1 j = 0
Arithmetic exception caught
After try block
```
当异常抛出时,控制立即转移到 `catch` 块的第一条语句,`try` 块中异常发生点之后的语句不会执行。
- **finally 块**:`finally` 块用于确保在方法返回之前执行特定的代码,无论 `try` 块中是否抛出异常。`finally` 块的语法如下:
```java
finally {
// 最后执行的清理代码
}
```
`finally` 块必须紧跟在 `catch` 块之后,如果没有 `catch` 块,则紧跟在 `try` 块之后。
以下是一个包含 `try`、`catch` 和 `finally` 块的示例:
```java
import java.io.IOException;
public class TryBlockTest {
public static void main(String[] args) {
int[] x = {10, 5, 0}; // 三个整数的数组
try {
System.out.println("First try block in main() entered");
System.out.println("result = " + divide(x, 0)); // 无错误
x[1] = 0; // 将导致除以零
System.out.println("result = " + divide(x, 0)); // 算术错误
x[1] = 1; // 重置以防止除以零
System.out.println("result = " + divide(x, 1)); // 索引错误
} catch(ArithmeticException e) {
System.out.println("Arithmetic exception caught in main()");
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Index-out-of-bounds exception caught in main()");
}
System.out.println("Outside first try block in main()");
System.out.println("\nPress Enter to exit");
try {
```
0
0
复制全文
相关推荐









