Java异常处理:全面解析与最佳实践
立即解锁
发布时间: 2025-08-18 02:21:33 阅读量: 3 订阅数: 12 

### Java异常处理:全面解析与最佳实践
#### 1. 异常捕获与转换的思考
在Java编程中,捕获仅在开发和单元测试期间抛出的编程错误,与捕获不会发生的错误一样,都没有太大意义。通常,只有当我们想要定义一个能捕获所有异常和错误的通用异常处理器时,才会去捕获它们,就如同说“如果出现任何问题”。如今,使用`catch(Throwable e)`来表达“如果出现任何问题”已成为必要,这是因为区分错误和运行时异常的编程约定逐渐模糊,导致错误和运行时异常被捕获的可能性相差无几。所以,将运行时异常转换为错误是没有意义的。
#### 2. 已检查异常的抛出与传播
方法或构造函数头的`throws`子句中的已检查异常,要么是显式抛出,要么是传播。显式抛出意味着在方法或构造函数体中能找到`throw`语句;而传播则是指方法调用或类实例创建表达式的计算导致异常被抛出。不过,“隐式抛出”这种说法不太准确,因为它暗示异常总是会被抛出,实际并非如此。这种显式抛出和传播异常的区别,在后续复杂异常的定义中很重要。
#### 3. 通用异常类的剖析
要讨论通用异常类,需从`throw`语句的角度思考。每个`throw`语句都可能需要声明一个新的异常类,但异常类很少只对应一个`throw`语句。例如,`CloneNotSupportedException`是简单异常,其所有实例都对应`Object`类的`native clone()`方法中的同一个`throw`语句。绝大多数异常类是复杂异常,对应多个`throw`语句。异常与`throw`语句的“映射”方式有三种:
- **直接映射**:如果异常类名就是被抛出的异常类的名称,则该异常直接映射到`throw`语句。
- **间接映射**:当涉及异常转换时,异常间接映射到`throw`语句。例如:
```java
try {
…
throw new LowLevelException();
…
} catch(LowLevelException e) {
throw new HighLevelException("detail message", e);
}
```
在这个例子中,`HighLevelException`间接映射到加粗的`throw`语句。
- **通用异常类映射**:通用异常类映射到其所有子类所映射的`throw`语句。
复杂异常类主要有以下几种:
| 异常类型 | 特点 | 示例 |
| --- | --- | --- |
| 常见异常类 | 通常是`java.lang`包中的运行时异常和错误,在许多不同包中显式抛出,一般是`RuntimeException`或`Error`的直接子类,且没有子类 | `NullPointerException` |
| 通用异常类 | 是`Throwable`类层次结构中的超类,又分为非功能组、高级异常和伞形异常 | 非功能组:`LinkageError`、`VirtualMachineError`;高级异常:`SocketException`、`RemoteException`、`SQLException`;伞形异常:`IOException` |
| 低级异常 | 除简单异常外的其他复杂异常类,其API文档倾向于列出异常被抛出的所有条件 | `OptionalDataException`、`UnmarshalException` |
#### 4. 低级异常的特性
简单异常对应单个`throw`语句的情况很少见,所以将其余复杂异常类定义为低级异常。低级异常的一个显著特点是,其API文档会列出异常被抛出的所有条件,每个条件代表一个或多个`throw`语句,这与高级异常只描述一般故障不同。例如,`java.io`包中的`OptionalDataException`,表示对象读取操作因未读取的原始数据或序列化对象数据结束而失败,可能在以下两种情况下抛出:
- 当流中的下一个元素是原始数据,却尝试读取对象时,`OptionalDataException`的`length`字段会设置为可立即从流中读取的原始数据的字节数,`eof`字段设置为`false`。
- 当尝试读取超过类定义的`readObject`或`readExternal`方法可消耗的数据末尾时,`eof`字段设置为`true`,`length`字段设置为`0`。
还有`java.rmi`包中的`UnmarshalException`,在解组远程方法调用的参数或结果时,如果出现以下任何情况都会抛出:
- 解组调用头时发生异常。
- 返回值的协议无效。
- 解组参数(服务器端)或返回值(客户端)时发生`java.io.IOException`。
- 解组参数或返回值时发生`java.lang.ClassNotFoundException`。
- 服务器端无法加载骨架(1.1存根协议需要骨架,1.2存根协议不需要)。
- 方法哈希无效(即缺少方法)。
- 解组远程对象的存根时,无法创建远程引用对象。
可以看出,`UnmarshalException`既直接又间接映射到多个不同的`throw`语句,由于它过于具体,不能被视为高级异常。
#### 5. 复杂异常命名的注意事项
命名对应多个`throw`语句的复杂异常时要格外小心。以`FileNotFoundException`为例,它表示尝试打开指定路径名的文件失败。`FileInputStream`、`FileOutputStream`和`RandomAccessFile`构造函数在文件不存在或文件存在但因某种原因不可访问(如尝试以写入方式打开只读文件)时会抛出该异常。然而,该异常类名并未表明文件存在但不可访问时也会抛出此异常。实际上,只要文件无法打开,都会抛出`FileNotFoundException`,这是命名不当的典型例
0
0
复制全文
相关推荐










