异常体系概述

Java 异常分类详解


一、异常体系概述

Java 中的所有可抛出对象都继承自 Throwable 类,它分为两大分支:

  • Error(错误):系统级错误,通常由 JVM 生成,表示不可恢复的严重问题
  • Exception(异常):程序级的异常,表示程序本身可以处理的问题

异常继承结构

Throwable
├── Error(系统错误,程序不需处理)
│   ├── VirtualMachineError(虚拟机错误)
│   │   ├── StackOverflowError(栈溢出)
│   │   └── OutOfMemoryError(内存溢出)
│   └── NoClassDefFoundError(类未找到)
│
└── Exception(程序异常)
    ├── RuntimeException(Unchecked Exception)(非受检异常,可不处理)
    │   ├── NullPointerException(空指针)
    │   ├── ArrayIndexOutOfBoundsException(数组越界)
    │   ├── ArithmeticException(算术异常/除零)
    │   ├── ClassCastException(类型转换)
    │   └── IllegalArgumentException(非法参数)
    │
    └── Checked Exception(受检异常,必须处理)
        ├── IOException(输入输出)
        ├── SQLException(数据库)
        ├── ClassNotFoundException(类未找到)
        └── FileNotFoundException(文件未找到)

二、Error(错误)

Error 表示 JVM 运行时的系统错误,通常由外部因素引起,程序无法主动捕获和处理。

错误类型 说明 常见场景
VirtualMachineError 虚拟机错误 JVM 本身出现问题
StackOverflowError 栈溢出错误 递归调用没有正确终止
OutOfMemoryError 内存溢出错误 对象创建过多,堆内存耗尽
NoClassDefFoundError 类定义未找到错误 编译时类存在,运行时缺失
OutOfMemoryError: Metaspace 元空间溢出 加载的类过多

示例代码

public class StackOverflowDemo {
    // 无限递归会导致 StackOverflowError
    public static void recursive() {
        recursive(); // 没有终止条件
    }

    public static void main(String[] args) {
        try {
            recursive();
        } catch (StackOverflowError e) {
            System.out.println("栈溢出错误发生!");
        }
    }
}

三、Exception(异常)

Exception 是程序运行过程中可以捕获和处理的异常,分为两大类:

3.1 运行时异常(RuntimeException)

也称为非受检异常(Unchecked Exception),由程序逻辑错误引起,编译器不强制要求捕获或声明。

异常类型 说明 示例
NullPointerException 空指针异常 调用 null 对象的方法
ArrayIndexOutOfBoundsException 数组越界异常 访问不存在的索引
StringIndexOutOfBoundsException 字符串越界异常 charAt() 传入非法索引
ArithmeticException 算术异常 整数除以零
ClassCastException 类型转换异常 强制转换不兼容的类型
IllegalArgumentException 非法参数异常 方法参数不合法
NumberFormatException 数字格式异常 Integer.parseInt("abc")

示例代码

public class RuntimeExceptionDemo {
    public static void main(String[] args) {
        // 1. 空指针异常
        String str = null;
        try {
            System.out.println(str.length());
        } catch (NullPointerException e) {
            System.out.println("空指针异常:" + e.getMessage());
        }

        // 2. 数组越界
        int[] arr = {1, 2, 3};
        try {
            System.out.println(arr[5]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界:" + e.getMessage());
        }

        // 3. 除零异常
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            System.out.println("算术异常:" + e.getMessage());
        }

        // 4. 类型转换异常
        Object obj = "Hello";
        try {
            Integer num = (Integer) obj;
        } catch (ClassCastException e) {
            System.out.println("类型转换异常:" + e.getMessage());
        }
    }
}

3.2 受检异常(Checked Exception)

也称为编译时异常,编译器强制要求捕获或声明抛出,由外部因素引起。

异常类型 说明 处理方式
IOException 输入输出异常 必须 try-catch 或 throws
SQLException 数据库异常 必须 try-catch 或 throws
ClassNotFoundException 类未找到异常 必须 try-catch 或 throws
FileNotFoundException 文件未找到异常 必须 try-catch 或 throws
InterruptedException 中断异常 必须 try-catch 或 throws
NoSuchMethodException 方法未找到异常 必须 try-catch 或 throws

示例代码

import java.io.FileReader;
import java.io.IOException;

public class CheckedExceptionDemo {

    // 方式一:捕获异常
    public void readFile() {
        try (FileReader reader = new FileReader("test.txt")) {
            int data;
            while ((data = reader.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            System.out.println("文件读取失败:" + e.getMessage());
        }
    }

    // 方式二:声明抛出
    public void readFileThrows() throws IOException {
        FileReader reader = new FileReader("test.txt");
        int data;
        while ((data = reader.read()) != -1) {
            System.out.print((char) data);
        }
        reader.close();
    }
}

四、异常处理最佳实践

4.1 异常捕获顺序

先捕获具体异常,再捕获通用异常:

try {
    // 业务代码
} catch (NullPointerException e) {
    // 先处理空指针
} catch (IOException e) {
    // 再处理IO异常
} catch (Exception e) {
    // 最后捕获通用异常
}

4.2 常见原则

原则 说明
异常要具体 捕获具体异常类型,而非泛型 Exception
不要吞掉异常 至少要记录日志
及时释放资源 使用 try-with-resources
避免大范围捕获 只捕获需要处理的异常
异常不能代替流程控制 不要用异常来做业务判断

4.3 try-with-resources 示例

// 传统写法
FileReader reader = null;
try {
    reader = new FileReader("test.txt");
    // 读取文件
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// try-with-resources 写法(推荐)
try (FileReader reader = new FileReader("test.txt")) {
    // 读取文件
} catch (IOException e) {
    e.printStackTrace();
}

五、总结

Throwable
├── Error(系统错误,程序不需处理)
│
└── Exception(程序异常)
    │ 
    ├── RuntimeException(Unchecked Exception)(非受检异常,可不处理)
    │
    └── Checked Exception(受检异常,必须处理)

总结对比表

类别 父类 是否受检 处理要求 典型场景
Error Throwable - 不需要处理 系统级错误(栈溢出、内存溢出)
RuntimeException Exception 非受检 可不处理 程序逻辑错误(空指针、越界)
Checked Exception Exception 受检 必须捕获或声明 外部资源问题(IO、SQL)
类别 是否受检 处理要求 典型场景
Error - 不需要处理 系统级错误
RuntimeException 非受检 可不处理 程序逻辑错误
Checked Exception 受检 必须捕获或声明 外部资源问题
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容