跳转到内容

Java异常体系

来自代码酷
Admin留言 | 贡献2025年5月12日 (一) 00:23的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

Java异常体系[编辑 | 编辑源代码]

概述[编辑 | 编辑源代码]

Java异常体系是Java语言中用于处理程序运行时错误的机制框架。当程序在运行过程中出现意外情况(如除以零、空指针访问等)时,Java会抛出(throw)一个异常对象,程序可以捕获(catch)并处理这个异常,从而保证程序的健壮性。

Java异常体系的核心特点是:

  • 继承层次结构:所有异常类型都是java.lang.Throwable的子类
  • 分类处理:分为检查型异常(Checked Exception)和非检查型异常(Unchecked Exception)
  • 传播机制:异常会沿着方法调用栈向上传播,直到被捕获或导致程序终止

异常分类[编辑 | 编辑源代码]

Java异常体系主要分为三大类:

classDiagram Throwable <|-- Error Throwable <|-- Exception Exception <|-- RuntimeException Exception <|-- IOException

1. Error[编辑 | 编辑源代码]

表示JVM本身的严重错误,应用程序通常无法处理。例如:

  • OutOfMemoryError
  • StackOverflowError
  • VirtualMachineError

2. 检查型异常(Checked Exception)[编辑 | 编辑源代码]

继承自Exception但不属于RuntimeException的异常,编译器会强制检查。常见例子:

  • IOException
  • SQLException
  • ClassNotFoundException

3. 非检查型异常(Unchecked Exception)[编辑 | 编辑源代码]

继承自RuntimeException的异常,编译器不强制处理。常见例子:

  • NullPointerException
  • ArrayIndexOutOfBoundsException
  • IllegalArgumentException

异常处理机制[编辑 | 编辑源代码]

Java通过五个关键字实现异常处理:try, catch, finally, throw, throws

基本语法[编辑 | 编辑源代码]

try {
    // 可能抛出异常的代码
} catch (ExceptionType1 e1) {
    // 处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
    // 处理ExceptionType2类型的异常
} finally {
    // 无论是否发生异常都会执行的代码
}

示例:文件读取[编辑 | 编辑源代码]

import java.io.*;

public class FileExample {
    public static void main(String[] args) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader("test.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            System.err.println("文件未找到: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("IO错误: " + e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                System.err.println("关闭文件时出错: " + e.getMessage());
            }
        }
    }
}

可能的输出:

文件未找到: test.txt (系统找不到指定的文件。)

自定义异常[编辑 | 编辑源代码]

可以创建自己的异常类来代表特定问题:

// 自定义检查型异常
class InsufficientFundsException extends Exception {
    private double amount;
    
    public InsufficientFundsException(double amount) {
        super("资金不足,缺少: " + amount);
        this.amount = amount;
    }
    
    public double getAmount() {
        return amount;
    }
}

// 使用示例
class BankAccount {
    private double balance;
    
    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(amount - balance);
        }
        balance -= amount;
    }
}

最佳实践[编辑 | 编辑源代码]

1. 具体异常优先:捕获最具体的异常类型,而不是直接捕获Exception 2. 不要忽略异常:至少记录异常信息 3. 合理使用finally:释放资源应放在finally块中 4. 避免空的catch块:这会隐藏错误 5. 异常与业务逻辑分离:不要用异常控制正常流程

异常链[编辑 | 编辑源代码]

Java支持异常链,可以将底层异常包装为高层异常:

try {
    // 可能抛出SQLException的代码
} catch (SQLException e) {
    throw new ServiceException("数据库操作失败", e);
}

性能考虑[编辑 | 编辑源代码]

异常处理会带来性能开销,特别是在频繁执行的代码路径中。对于可预见的错误条件,考虑使用返回值而不是异常。

异常实例的构造开销主要来自:

  • 填充异常栈轨迹(可通过重写fillInStackTrace()优化)
  • 异常对象的创建本身

数学表示[编辑 | 编辑源代码]

异常处理的概率模型可以表示为:

解析失败 (语法错误): {\displaystyle P(程序终止) = \prod_{i=1}^{n} (1 - P(处理异常_i)) }

其中解析失败 (语法错误): {\displaystyle P(处理异常_i)} 表示第i层异常被处理的概率。

实际案例[编辑 | 编辑源代码]

电商系统库存检查

public class InventoryService {
    public void reserveItem(String itemId, int quantity) 
            throws InventoryException {
        try {
            // 检查库存
            int available = checkInventoryDB(itemId);
            if (available < quantity) {
                throw new InventoryException(
                    "库存不足,请求: " + quantity + 
                    ", 可用: " + available);
            }
            // 更新库存...
        } catch (SQLException e) {
            throw new InventoryException("数据库访问失败", e);
        }
    }
}

常见面试问题[编辑 | 编辑源代码]

1. Error和Exception的区别是什么? 2. 检查型异常和非检查型异常的主要区别? 3. finally块在什么情况下不会执行? 4. 解释异常链的概念及其用途 5. 为什么不应该用异常来控制程序流程?