1. 异常概述 #
异常是程序执行过程中出现的意外事件,会中断程序的正常流程。Java使用异常处理机制来处理运行时错误,使得程序更加健壮。
2. 异常层次结构 #
Java的所有异常都是java.lang.Throwable
类的子类,主要分为两大类:
- Error:表示严重的问题,通常是不可恢复的系统级错误。
- Exception:表示可以被程序处理的异常情况。
Throwable
/ \
Error Exception
\
RuntimeException
3. 检查型异常vs非检查型异常 #
3.1 检查型异常(Checked Exceptions) #
- 除了
RuntimeException
及其子类之外的所有异常。 - 必须在代码中显式处理或声明抛出。
- 例如:
IOException
,SQLException
3.2 非检查型异常(Unchecked Exceptions) #
RuntimeException
及其子类。- 不需要在代码中显式处理。
- 例如:
NullPointerException
,ArrayIndexOutOfBoundsException
4. 异常处理 #
4.1 try-catch 块 #
try {
// 可能抛出异常的代码
} catch (ExceptionType1 e1) {
// 处理 ExceptionType1
} catch (ExceptionType2 e2) {
// 处理 ExceptionType2
} finally {
// 无论是否发生异常都会执行的代码
}
4.2 多重捕获 #
Java 7引入的特性,允许在一个catch块中捕获多个异常:
try {
// 可能抛出异常的代码
} catch (IOException | SQLException e) {
// 处理 IOException 或 SQLException
}
4.3 try-with-resources #
Java 7引入的特性,用于自动关闭实现了AutoCloseable
接口的资源:
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
// 使用 br
} catch (IOException e) {
// 处理异常
}
5. 抛出异常 #
使用throw
关键字抛出异常:
if (condition) {
throw new IllegalArgumentException("Invalid argument");
}
6. 声明异常 #
使用throws
关键字在方法签名中声明可能抛出的检查型异常:
public void readFile(String path) throws IOException {
// 方法实现
}
7. 自定义异常 #
创建自定义异常类:
public class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
8. 异常链 #
在捕获一个异常后抛出另一个异常,同时保留原始异常信息:
try {
// 可能抛出异常的代码
} catch (OriginalException e) {
throw new WrapperException("A problem occurred", e);
}
9. 最佳实践 #
- 只在异常情况下使用异常。
- 捕获具体的异常,而不是笼统地捕获
Exception
。 - 不要捕获
Throwable
或Error
。 - 在
finally
块中清理资源,或使用try-with-resources。 - 记录异常信息,有助于调试。
- 适当地封装异常,不要暴露敏感信息。
10. 常见异常类型 #
NullPointerException
: 尝试使用null对象ArrayIndexOutOfBoundsException
: 数组索引越界IllegalArgumentException
: 方法接收到不合法的参数IOException
: 输入/输出操作失败SQLException
: 数据库访问错误
理解和正确使用Java异常处理机制可以显著提高程序的健壮性和可维护性。通过合理的异常处理,我们可以优雅地处理错误情况,提供有意义的错误消息,并确保程序能够从错误中恢复或优雅地退出。
11. 自定义异常的类型 #
11.1 检查型异常 vs 非检查型异常 #
在之前的例子中:
public class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
这个CustomException
是一个检查型异常。这是因为它直接继承自Exception
类,而不是RuntimeException
类。
11.2 自定义检查型异常 #
- 继承自
Exception
类或其任何子类(除了RuntimeException
及其子类) - 必须被显式捕获或在方法签名中声明抛出
- 用于表示程序可以合理地预期和恢复的异常情况
例如:
public class CustomCheckedException extends Exception {
public CustomCheckedException(String message) {
super(message);
}
}
11.3 自定义非检查型异常 #
- 继承自
RuntimeException
类或其子类 - 不需要显式捕获或声明
- 通常用于表示编程错误或不可恢复的状态
例如:
public class CustomUncheckedException extends RuntimeException {
public CustomUncheckedException(String message) {
super(message);
}
}
11.4 选择建议 #
-
使用检查型异常:
- 当你希望强制调用者处理异常情况
- 当异常是可以预期和恢复的
- 例如:文件操作、网络连接问题
-
使用非检查型异常:
- 当异常表示编程错误(如空指针、非法参数)
- 当异常是不可恢复的
- 当你不希望强制每个调用者都处理这个异常
11.5 示例 #
检查型异常示例:
public void readImportantFile() throws CustomCheckedException {
if (!fileExists()) {
throw new CustomCheckedException("Important file does not exist");
}
// 读取文件的代码
}
// 使用时必须处理或声明抛出
try {
readImportantFile();
} catch (CustomCheckedException e) {
// 处理异常
}
非检查型异常示例:
public void processData(String data) {
if (data == null) {
throw new CustomUncheckedException("Data cannot be null");
}
// 处理数据的代码
}
// 使用时不强制处理
processData(someData);