一、异常整体继承体系(树形结构图)

Throwable (顶层根类)
├─ Error (系统级错误,无法处理)
└─ Exception (程序级异常,可捕获处理)
   ├─ RuntimeException (运行时异常/非受检异常)
   └─ 编译时异常 (受检异常/非运行时异常)

核心概念

  1. ThrowableJava 中所有异常、错误的最顶层父类,只有它的子类才能被异常处理机制识别。
  2. Error 错误由 JVM 底层抛出,程序无法捕获、无法修复,属于系统严重故障,只能终止程序。
  3. Exception 异常由程序逻辑、外部资源问题产生,开发者可以通过代码捕获、处理、恢复程序运行

二、Exception 详细分类

1. 运行时异常(非受检异常)

  • 父类:RuntimeException
  • 产生原因:程序员代码逻辑写错
  • 特点:编译阶段不报错、不强制处理程序运行时才会崩溃抛出
  • 常见类型:
    • NullPointerException 空指针异常
    • ArrayIndexOutOfBoundsException 数组下标越界
    • ArithmeticException 算术异常(整数除 0)
    • ClassCastException 类型强制转换异常

代码示例

public class RuntimeExceptionDemo {
    public static void main(String[] args) {
        String str = null;
        str.length(); // 空指针,运行时报错,编译不报错
    }
}

2. 编译时异常(受检异常 / 非运行时异常)

  • 不属于 RuntimeException 子类
  • 产生原因:外部资源问题(文件、网络、IO)
  • 特点:编译阶段强制要求处理不写处理代码,直接编译爆红,无法运行
  • 常见类型:
    • FileNotFoundException 文件未找到
    • IOException IO 读写异常
    • SQLException 数据库操作异常

代码示例

import java.io.FileReader;

public class CheckedExceptionDemo {
    public static void main(String[] args) {
        // 编译时异常,必须处理,否则编译失败
        FileReader fr = new FileReader("a.txt");
    }
}

三、Error 常见类型(不可处理)

都是 JVM 级致命错误,不能 try-catch 捕获,只能优化代码

  1. StackOverflowError 栈溢出成因:递归没有终止条件、方法无限嵌套调用代码示例:
public class ErrorDemo {
    public static void test() {
        test(); // 无限递归
    }
    public static void main(String[] args) {
        test();
    }
}
  1. OutOfMemoryError 内存溢出成因:创建过多对象、大集合无限存元素、内存泄漏。

四、异常的两种处理方案

1. try...catch...finally 本地捕获处理

结构作用

  • try:包裹可能抛出异常的敏感代码
  • catch:捕获对应类型异常,自定义处理逻辑;支持多 catch 分级捕获
  • finally:无论是否出现异常、无论是否 return,一定会执行
  • 适用场景:关闭 IO 流、数据库连接、释放资源

基础语法 + 多 catch 示例

public class TryCatchDemo {
    public static void main(String[] args) {
        try {
            int a = 1 / 0;
            int[] arr = new int[2];
            arr[5] = 10;
        } catch (ArithmeticException e) {
            System.out.println("算术异常:除零错误");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界异常");
        } finally {
            System.out.println("资源释放,必定执行");
        }
    }
}

重要规则

  • finally 唯一不执行情况:System.exit(0) 直接终止 JVM。

2. throws 声明式抛出异常

  • 作用:当前方法不处理异常,把异常抛给调用者处理
  • 位置:写在方法签名后面
  • 可以一次性抛出多个异常,逗号分隔
  • 规则:子类重写父类方法,抛出异常范围不能比父类更大

代码示例:

public class ThrowsDemo {
    public static void main(String[] args) throws Exception {
        readFile();
    }

    public static void readFile() throws Exception {
        FileReader fr = new FileReader("a.txt");
    }
}

五、手动抛出异常:throw

1. 关键字区别

  • throw方法内部,主动手动抛出一个异常对象
  • throws方法声明上,被动声明抛出异常类型

2. 用法示例

public class ThrowDemo {
    public static void checkAge(int age) {
        if(age < 18){
            // 手动抛出异常,自定义提示信息
            throw new RuntimeException("年龄未满18,禁止访问");
        }
    }

    public static void main(String[] args) {
        checkAge(16);
    }
}

六、补充高频必考知识点

  1. 运行时异常 vs 编译时异常
    • 运行时:代码逻辑错,编译不强制处理
    • 编译时:外部资源错,编译必须处理
  2. Error 和 Exception 本质区别
    • Error:JVM 系统级错误,不可处理
    • Exception:程序业务异常,可捕获恢复
  3. finally 能不能省略?可以;try 必须搭配 catch 或 finally 至少一个
  4. e.printStackTrace () 作用打印异常类型、异常信息、代码出错位置,调试必备。

七、终极思维导图(文字版结构图)

Throwable
├─ Error
│   ├─ StackOverflowError 栈溢出
│   └─ OutOfMemoryError 内存溢出
└─ Exception
    ├─ RuntimeException(运行时异常)
    │   ├─ 空指针、数组越界、除零、类型转换
    └─ 编译时异常(受检异常)
        ├─ FileNotFound、IO、SQL异常

 

更多推荐