Checked Exception 和 Unchecked Exception 的详细对比与示例说明,涵盖核心概念、继承关系、使用场景及最佳实践

发布于:2025-06-08 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、核心区别

​特性​ ​Checked Exception​ ​Unchecked Exception​
​继承关系​ 继承自 Exception 类 继承自 RuntimeException 类
​编译时检查​ 必须显式处理(捕获或声明抛出),否则编译失败 无需强制处理,编译器不检查
​用途​ 表示可恢复的外部错误(如文件不存在、网络中断) 表示编程逻辑错误(如空指针、数组越界)
​典型示例​ IOExceptionSQLException NullPointerExceptionArithmeticException

二、Checked Exception

1. 定义与特点

  • ​必须处理​​:在方法内抛出时,必须在方法签名中声明(throws),或在方法内部捕获(try-catch)。
  • ​可恢复性​​:通常表示外部环境问题,可通过重试、回退等操作恢复。
  • ​Java API 示例​​:IOExceptionSQLExceptionClassNotFoundException

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 示例​​:NullPointerExceptionArrayIndexOutOfBoundsExceptionArithmeticException

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

  • 不要将业务逻辑错误(如参数校验失败)封装为 Checked Exception。
  • 示例错误用法:
    java
    复制
    // ❌ 不推荐:参数校验应抛出 Unchecked Exception
    public void setName(String name) throws InvalidNameException {
        if (name == null) {
            throw new InvalidNameException("姓名不能为空");
        }
    }

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)。