一、核心区别
特性 |
Checked Exception |
Unchecked Exception |
继承关系 |
继承自 Exception 类 |
继承自 RuntimeException 类 |
编译时检查 |
必须显式处理(捕获或声明抛出),否则编译失败 |
无需强制处理,编译器不检查 |
用途 |
表示可恢复的外部错误(如文件不存在、网络中断) |
表示编程逻辑错误(如空指针、数组越界) |
典型示例 |
IOException , SQLException |
NullPointerException , ArithmeticException |
二、Checked Exception
1. 定义与特点
- 必须处理:在方法内抛出时,必须在方法签名中声明(
throws
),或在方法内部捕获(try-catch
)。
- 可恢复性:通常表示外部环境问题,可通过重试、回退等操作恢复。
- Java API 示例:
IOException
, SQLException
, ClassNotFoundException
。
2. 代码示例
(1) 文件读取(必须处理异常)
java
复制
import java.io.FileReader;
import java.io.IOException;
public class FileProcessor {
public void readFile(String path) throws IOException { // 声明抛出 Checked Exception
FileReader reader = new FileReader(path);
// 文件操作...
}
}
// 调用方必须处理异常
public class Main {
public static void main(String[] args) {
FileProcessor processor = new FileProcessor();
try {
processor.readFile("test.txt");
} catch (IOException e) {
System.out.println("文件读取失败: " + e.getMessage());
}
}
}
(2) 数据库连接(声明抛出)
java
复制
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseConnector {
public Connection connect() throws SQLException { // Checked Exception
String url = "jdbc:mysql://localhost:3306/mydb";
return DriverManager.getConnection(url, "user", "password");
}
}
// 调用方处理异常
public class Main {
public static void main(String[] args) {
DatabaseConnector connector = new DatabaseConnector();
try {
Connection conn = connector.connect();
} catch (SQLException e) {
System.out.println("数据库连接失败: " + e.getMessage());
}
}
}
三、Unchecked Exception
1. 定义与特点
- 无需强制处理:编译器不强制要求捕获或声明。
- 不可恢复性:通常是程序逻辑错误,需通过修复代码解决。
- Java API 示例:
NullPointerException
, ArrayIndexOutOfBoundsException
, ArithmeticException
。
2. 代码示例
(1) 空指针异常(运行时错误)
java
复制
public class UserService {
public void getUser(String name) {
User user = findUser(name);
System.out.println(user.getName()); // 若 user 为 null,抛出 NullPointerException
}
private User findUser(String name) {
// 模拟未找到用户
return null;
}
}
// 调用方无需处理,但运行时会崩溃
public class Main {
public static void main(String[] args) {
UserService service = new UserService();
service.getUser("Alice"); // 抛出 NullPointerException
}
}
(2) 数组越界(逻辑错误)
java
复制
public class Calculator {
public int divide(int a, int b) {
return a / b; // 若 b=0,抛出 ArithmeticException
}
}
// 调用方无需处理,但运行时崩溃
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
System.out.println(calculator.divide(10, 0)); // 抛出 ArithmeticException
}
}
四、何时使用哪种异常?
1. 使用 Checked Exception 的场景
- 可恢复的外部错误:如文件不存在、数据库连接失败。
- 强制调用方处理:确保错误不会被忽略。
java
复制
public void saveDataToFile(String path) throws IOException {
// 文件操作可能失败,调用方必须处理
}
2. 使用 Unchecked Exception 的场景
- 编程逻辑错误:如参数校验失败、空指针。
- 无需强制处理:错误应由开发者自行修复。
java
复制
public void validateAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数"); // Unchecked
}
}
五、最佳实践
1. 避免过度使用 Checked Exception
2. 优先使用标准异常
- 使用 Java 内置异常(如
IllegalArgumentException
)代替自定义 Checked Exception。
java
复制
public void processInput(String input) {
if (input.isEmpty()) {
throw new IllegalArgumentException("输入不能为空"); // 简洁且无需处理
}
}
3. 合理自定义异常
- 当需要明确业务语义时,自定义 Unchecked Exception。
java
复制
// 自定义业务异常(Unchecked)
public class PaymentFailedException extends RuntimeException {
public PaymentFailedException(String message) {
super(message);
}
}
// 使用
public void pay(double amount) {
if (amount <= 0) {
throw new PaymentFailedException("金额必须大于零");
}
}
六、对比总结
场景 |
Checked Exception |
Unchecked Exception |
处理要求 |
必须显式处理 |
无需强制处理 |
典型用途 |
外部资源错误(文件、网络、数据库) |
程序逻辑错误(空指针、计算错误) |
代码可读性 |
可能冗余(需大量 try-catch 或 throws) |
更简洁(直接暴露问题) |
恢复可能性 |
可能通过重试、回退等恢复 |
通常需修改代码逻辑 |
七、实战示例:订单支付场景
java
复制
public class PaymentService {
// Checked Exception:外部支付接口调用失败
public void callPaymentAPI(double amount) throws PaymentGatewayException {
boolean success = false; // 模拟支付接口失败
if (!success) {
throw new PaymentGatewayException("支付接口调用失败");
}
}
// Unchecked Exception:参数校验失败
public void validateOrder(Order order) {
if (order.getItems().isEmpty()) {
throw new IllegalArgumentException("订单商品不能为空");
}
}
}
// 调用方处理 Checked Exception
public class Main {
public static void main(String[] args) {
PaymentService service = new PaymentService();
try {
service.callPaymentAPI(100.0);
} catch (PaymentGatewayException e) {
System.out.println("支付失败: " + e.getMessage());
}
// Unchecked Exception 无需处理(但应避免触发)
service.validateOrder(new Order()); // 抛出 IllegalArgumentException
}
}
八、总结
- Checked Exception:用于可恢复的外部错误,强制调用方处理,但需避免滥用。
- Unchecked Exception:用于编程逻辑错误,无需强制处理,提高代码简洁性。
- 核心原则:
- 不要忽略异常:至少记录日志或清理资源。
- 避免过度设计:优先使用标准异常,仅在必要时自定义。
- 明确语义:通过异常类型传递错误信息(如
InvalidInputException
)。