Skip to content

异常处理

异常体系

异常层次结构

Throwable
├── Error(错误)
│   ├── VirtualMachineError
│   ├── OutOfMemoryError
│   └── StackOverflowError
└── Exception(异常)
    ├── IOException
    │   ├── FileNotFoundException
    │   └── EOFException
    ├── SQLException
    ├── RuntimeException(运行时异常)
    │   ├── NullPointerException
    │   ├── ArrayIndexOutOfBoundsException
    │   ├── ArithmeticException
    │   ├── ClassCastException
    │   └── IllegalArgumentException
    └── ...

异常分类

类型说明示例
ErrorJVM无法处理的严重错误OutOfMemoryError
受检异常编译时必须处理的异常IOException、SQLException
运行时异常编译时不强制处理NullPointerException

try-catch-finally

基本语法

java
public class ExceptionDemo {
    public static void main(String[] args) {
        try {
            // 可能出错的代码
            int result = 10 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            // 异常处理
            System.out.println("除数不能为0");
            System.out.println("异常信息: " + e.getMessage());
        } finally {
            // 无论是否异常都会执行
            System.out.println("finally块执行");
        }
    }
}

多个catch块

java
try {
    int[] arr = new int[5];
    arr[10] = 100;  // ArrayIndexOutOfBoundsException
    String s = null;
    s.length();     // NullPointerException
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("数组越界: " + e.getMessage());
} catch (NullPointerException e) {
    System.out.println("空指针异常: " + e.getMessage());
} catch (Exception e) {
    System.out.println("其他异常: " + e.getMessage());
}

Java 7+ 多异常捕获

java
try {
    // 可能抛出多种异常的代码
} catch (IOException | SQLException e) {
    System.out.println("IO或SQL异常: " + e.getMessage());
}

finally执行顺序

java
public class FinallyDemo {
    public static int test() {
        try {
            return 1;
        } finally {
            // finally在return之前执行
            System.out.println("finally执行");
        }
    }
    
    public static void main(String[] args) {
        System.out.println(test());
    }
}
// 输出: finally执行 → 1

throw和throws

throw抛出异常

java
public class ThrowDemo {
    public static void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("年龄必须在0-150之间");
        }
        System.out.println("年龄设置成功: " + age);
    }
    
    public static void main(String[] args) {
        try {
            setAge(-5);
        } catch (IllegalArgumentException e) {
            System.out.println("错误: " + e.getMessage());
        }
    }
}

throws声明异常

java
import java.io.FileInputStream;
import java.io.IOException;

public class ThrowsDemo {
    // 声明方法可能抛出的异常
    public static void readFile(String path) throws IOException {
        FileInputStream fis = new FileInputStream(path);
        fis.close();
    }
    
    public static void main(String[] args) {
        try {
            readFile("test.txt");
        } catch (IOException e) {
            System.out.println("文件读取失败: " + e.getMessage());
        }
    }
}

throw vs throws

throwthrows
抛出异常对象声明方法可能抛出的异常
在方法体内使用在方法签名上使用
后跟异常对象后跟异常类型

自定义异常

自定义受检异常

java
public class InsufficientBalanceException extends Exception {
    private double balance;
    private double amount;
    
    public InsufficientBalanceException(double balance, double amount) {
        super("余额不足!当前余额: " + balance + ", 需要金额: " + amount);
        this.balance = balance;
        this.amount = amount;
    }
    
    public double getBalance() {
        return balance;
    }
    
    public double getAmount() {
        return amount;
    }
}

自定义运行时异常

java
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
    
    public UserNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

使用自定义异常

java
public class BankAccount {
    private double balance;
    
    public BankAccount(double balance) {
        this.balance = balance;
    }
    
    public void withdraw(double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            throw new InsufficientBalanceException(balance, amount);
        }
        balance -= amount;
        System.out.println("取款成功,余额: " + balance);
    }
}

// 使用
BankAccount account = new BankAccount(1000);
try {
    account.withdraw(2000);
} catch (InsufficientBalanceException e) {
    System.out.println(e.getMessage());
}

try-with-resources

Java 7+ 自动资源管理

java
// 传统方式
FileInputStream fis = null;
try {
    fis = new FileInputStream("test.txt");
    // 使用资源
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// try-with-resources
try (FileInputStream fis = new FileInputStream("test.txt")) {
    // 使用资源
    // 自动关闭
} catch (IOException e) {
    e.printStackTrace();
}

多个资源

java
try (FileInputStream fis = new FileInputStream("input.txt");
     FileOutputStream fos = new FileOutputStream("output.txt")) {
    int data;
    while ((data = fis.read()) != -1) {
        fos.write(data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

自定义可关闭资源

java
public class MyResource implements AutoCloseable {
    private String name;
    
    public MyResource(String name) {
        this.name = name;
        System.out.println(name + " 创建");
    }
    
    public void doSomething() {
        System.out.println(name + " 使用中");
    }
    
    @Override
    public void close() {
        System.out.println(name + " 关闭");
    }
}

// 使用
try (MyResource r1 = new MyResource("资源1");
     MyResource r2 = new MyResource("资源2")) {
    r1.doSomething();
    r2.doSomething();
}
// 输出: 资源1创建 → 资源2创建 → 使用中 → 资源2关闭 → 资源1关闭

异常链

java
public class ExceptionChain {
    public static void main(String[] args) {
        try {
            method1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void method1() throws Exception {
        try {
            method2();
        } catch (IOException e) {
            // 包装异常,保留原始异常
            throw new Exception("处理文件时出错", e);
        }
    }
    
    public static void method2() throws IOException {
        throw new IOException("文件不存在");
    }
}

异常最佳实践

1. 只捕获能处理的异常

java
// 错误做法
try {
    // 很多代码
} catch (Exception e) {
    // 捕获所有异常
}

// 正确做法
try {
    file.read();
} catch (IOException e) {
    // 只捕获IO异常
}

2. 不要忽略异常

java
// 错误做法
try {
    file.read();
} catch (IOException e) {
    // 空catch块,忽略异常
}

// 正确做法
try {
    file.read();
} catch (IOException e) {
    log.error("读取文件失败", e);
    throw new RuntimeException("读取文件失败", e);
}

3. 使用具体异常类型

java
// 错误做法
throw new Exception("错误");

// 正确做法
throw new IllegalArgumentException("参数不能为空");

4. 提供有意义的异常信息

java
// 错误做法
throw new IllegalArgumentException("错误");

// 正确做法
throw new IllegalArgumentException("用户名不能为空");

5. 尽早失败

java
public void process(String name, int age) {
    // 参数校验放在方法开头
    if (name == null || name.isEmpty()) {
        throw new IllegalArgumentException("姓名不能为空");
    }
    if (age < 0 || age > 150) {
        throw new IllegalArgumentException("年龄必须在0-150之间");
    }
    
    // 正常业务逻辑
}

常见异常

异常原因解决方案
NullPointerException访问null对象的成员添加null检查
ArrayIndexOutOfBoundsException数组索引越界检查索引范围
ArithmeticException算术错误(如除零)检查除数
ClassCastException类型转换错误使用instanceof检查
NumberFormatException数字格式错误校验输入格式
IllegalArgumentException非法参数检查参数有效性