第44章

Java异常处理

掌握try-catch-finally语句与异常处理最佳实践

学习目标

Java异常处理概述

异常处理是Java编程中的重要概念,它允许程序在运行时优雅地处理错误情况。Java提供了一套完整的异常处理机制,通过try-catch-finally语句来捕获和处理异常,确保程序的健壮性和稳定性。

什么是异常?

异常是程序执行过程中发生的事件,它会中断程序的正常执行流程。Java中的异常是一个对象,它封装了错误信息和发生错误时的程序状态。

检查异常(Checked Exception)

示例:
try {
    FileReader file = new FileReader("file.txt");
} catch (FileNotFoundException e) {
    System.out.println("文件未找到: " + e.getMessage());
}
  • 编译时必须处理
  • 继承自Exception类
  • 如IOException、SQLException
  • 必须用try-catch或throws处理

运行时异常(Runtime Exception)

示例:
try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("除零错误: " + e.getMessage());
}
  • 运行时可能发生
  • 继承自RuntimeException类
  • 如NullPointerException、ArrayIndexOutOfBoundsException
  • 可以选择性处理

错误(Error)

示例:
// Error通常不应该被捕获
// 如OutOfMemoryError、StackOverflowError
public void recursiveMethod() {
    recursiveMethod(); // 可能导致StackOverflowError
}
  • 系统级严重错误
  • 继承自Error类
  • 如OutOfMemoryError、StackOverflowError
  • 通常不应该被捕获

try-catch-finally语句详解

基本语法结构

try-catch-finally基本语法:
try {
    // 可能抛出异常的代码
    // 受保护的代码块
} catch (ExceptionType1 e1) {
    // 处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
    // 处理ExceptionType2类型的异常
} finally {
    // 无论是否发生异常都会执行的代码
    // 通常用于资源清理
}

执行流程说明

异常处理执行顺序:

  1. try块:执行可能抛出异常的代码
  2. catch块:如果发生异常,执行相应的catch块
  3. finally块:无论是否发生异常都会执行
  4. 后续代码:继续执行try-catch-finally之后的代码
完整示例:
public class BasicExceptionHandling {
    public static void main(String[] args) {
        System.out.println("程序开始执行");
        
        try {
            System.out.println("进入try块");
            int[] numbers = {1, 2, 3};
            System.out.println("访问数组元素: " + numbers[5]); // 会抛出异常
            System.out.println("这行代码不会执行");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕获到异常: " + e.getMessage());
            System.out.println("异常类型: " + e.getClass().getSimpleName());
        } finally {
            System.out.println("finally块总是会执行");
        }
        
        System.out.println("程序继续执行");
    }
}
💻 查看完整代码 - 在线IDE体验

Java异常类层次结构

Java中的所有异常类都继承自Throwable类,形成了一个完整的异常类层次结构。

异常类 类型 描述 常见子类
Throwable 根类 所有异常和错误的超类 Exception, Error
Exception 检查异常 程序可以处理的异常 IOException, SQLException
RuntimeException 运行时异常 运行时可能发生的异常 NullPointerException, IllegalArgumentException
Error 错误 系统级严重错误 OutOfMemoryError, StackOverflowError
IOException 检查异常 输入输出操作异常 FileNotFoundException, EOFException
NullPointerException 运行时异常 空指针引用异常 -

异常处理最佳实践

异常处理原则与技巧

好的实践

// 1. 具体异常处理
try {
    processFile("data.txt");
} catch (FileNotFoundException e) {
    logger.error("文件未找到: " + e.getMessage());
    // 提供备用方案
    useDefaultData();
} catch (IOException e) {
    logger.error("文件读取错误: " + e.getMessage());
    throw new ProcessingException("数据处理失败", e);
}

// 2. 资源自动管理
try (FileReader reader = new FileReader("file.txt")) {
    // 使用资源
} // 自动关闭资源
  • 捕获具体的异常类型
  • 提供有意义的错误信息
  • 使用try-with-resources
  • 记录异常日志

应该避免

// 1. 捕获所有异常
try {
    riskyOperation();
} catch (Exception e) {
    // 太宽泛的异常捕获
}

// 2. 忽略异常
try {
    riskyOperation();
} catch (Exception e) {
    // 什么都不做 - 错误做法
}

// 3. 异常控制流程
try {
    return array[index];
} catch (ArrayIndexOutOfBoundsException e) {
    return null; // 用异常控制正常流程
}
  • 捕获过于宽泛的异常
  • 忽略或隐藏异常
  • 用异常控制程序流程
  • 在finally中抛出异常

自定义异常

当Java内置的异常类不能满足需求时,可以创建自定义异常类来更好地表达特定的错误情况。

自定义异常示例:
// 自定义检查异常
public class InsufficientBalanceException extends Exception {
    private double balance;
    private double amount;
    
    public InsufficientBalanceException(double balance, double amount) {
        super(String.format("余额不足:当前余额%.2f,尝试提取%.2f", balance, amount));
        this.balance = balance;
        this.amount = amount;
    }
    
    public double getBalance() { return balance; }
    public double getAmount() { return amount; }
}

// 自定义运行时异常
public class InvalidAccountException extends RuntimeException {
    public InvalidAccountException(String message) {
        super(message);
    }
    
    public InvalidAccountException(String message, Throwable cause) {
        super(message, cause);
    }
}

// 使用自定义异常
public class BankAccount {
    private double balance;
    
    public void withdraw(double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            throw new InsufficientBalanceException(balance, amount);
        }
        balance -= amount;
    }
}

自定义异常设计原则:

  • 继承合适的异常类(Exception或RuntimeException)
  • 提供有意义的异常名称和消息
  • 包含相关的错误信息
  • 提供多个构造方法
  • 考虑异常的序列化

章节总结