教程中心 / Java教程 / 异常处理

异常处理

20分钟 核心概念

引言:什么是异常?

异常(Exception)是程序在运行过程中发生的错误事件。Java的异常处理机制让我们能够捕获这些错误并做出适当的处理,而不是让程序崩溃。

异常类比

异常就像生活中的意外情况:

正常流程:出门 → 上班 → 完成工作
异常情况:出门 → 遇到堵车(异常)→ 绕道走 → 继续上班

如果没有异常处理:
出门 → 遇到堵车 → 程序崩溃

有异常处理:
出门 → 遇到堵车(捕获异常)→ 绕道 → 继续上班

异常的分类

类型说明是否需要处理
Error程序无法处理的严重错误,如内存溢出不需要(也无法处理)
RuntimeException运行时异常,如空指针、数组越界可以选择不处理(但最好处理)
受检查异常必须处理的异常,如IOException必须处理

常见的运行时异常

  • NullPointerException:空指针异常,调用null对象的方法
  • ArrayIndexOutOfBoundsException:数组越界
  • ArithmeticException:算术异常,如除以0
  • ClassCastException:类型转换异常
  • IllegalArgumentException:非法参数异常

try-catch-finally

基本语法

try {
    // 可能发生异常的代码
} catch (异常类型1 变量名) {
    // 处理异常类型1
} catch (异常类型2 变量名) {
    // 处理异常类型2
} finally {
    // 无论是否发生异常都会执行的代码
}

示例:捕获除零异常

public class ExceptionDemo {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30};
        int index = 3;

        try {
            System.out.println("尝试访问数组...");
            int result = numbers[index] / 0;
            System.out.println("不会执行到这里");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕获到数组越界异常: " + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("捕获到算术异常: " + e.getMessage());
        } finally {
            System.out.println("finally代码块总是执行");
        }

        System.out.println("程序继续执行...");
    }
}

执行流程:

  1. 执行try块中的代码
  2. 如果发生异常,停止执行try块,立即跳到catch匹配
  3. 执行catch块中的处理代码
  4. 最后执行finally块中的代码

catch的顺序

异常捕获必须从小到大(子类在前,父类在后):

try {
    // 可能发生多种异常的代码
} catch (NullPointerException e) {
    // 先捕获具体的异常
} catch (Exception e) {
    // 再捕获更通用的异常
}

printStackTrace() vs getMessage()

try {
    String str = null;
    System.out.println(str.length());  // 触发NullPointerException
} catch (NullPointerException e) {
    // 打印完整的异常堆栈信息(包含方法调用路径)
    e.printStackTrace();

    // 仅打印异常信息
    System.out.println("异常信息: " + e.getMessage());

    // 获取异常类型名称
    System.out.println("异常类型: " + e.getClass().getName());
}

throw与throws

throw - 抛出异常

throw用于在代码中主动抛出异常。

public class ThrowDemo {
    public static void main(String[] args) {
        int age = -5;

        if (age < 0) {
            // 主动抛出异常
            throw new IllegalArgumentException("年龄不能为负数: " + age);
        }

        System.out.println("年龄: " + age);
    }
}

throws - 声明异常

throws用于在方法声明时声明可能抛出的异常。

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

public class ThrowsDemo {

    // 声明此方法可能抛出IOException
    public static void readFile() throws IOException {
        FileReader reader = new FileReader("test.txt");
        reader.read();
        reader.close();
    }

    public static void main(String[] args) {
        try {
            readFile();
        } catch (IOException e) {
            System.out.println("文件读取失败: " + e.getMessage());
        }
    }
}

throw vs throws:

  • throw:在方法内部使用,后面跟一个异常对象
  • throws:在方法声明处使用,后面跟异常类型(多个用逗号分隔)

自定义异常

创建自定义异常

public class AgeException extends Exception {
    public AgeException() {
        super();
    }

    public AgeException(String message) {
        super(message);
    }
}

使用自定义异常

public class Person {
    private int age;

    public void setAge(int age) throws AgeException {
        if (age < 0 || age > 150) {
            throw new AgeException("年龄不合法: " + age);
        }
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

// 使用
Person person = new Person();
try {
    person.setAge(-5);
} catch (AgeException e) {
    System.out.println("捕获自定义异常: " + e.getMessage());
}

异常链

异常链允许我们保存原始异常的信息,同时添加新的上下文。

try {
    // 原始操作,可能抛出异常
    int[] arr = {1, 2, 3};
    int result = arr[10];
} catch (ArrayIndexOutOfBoundsException e) {
    // 包装成新的异常,保留原始异常
    throw new RuntimeException("获取数据失败", e);
}

最佳实践

捕获具体异常:尽量捕获具体异常类型,而不是Exception
不要吞掉异常:不要只写catch空块,至少要记录日志
关闭资源:在finally中关闭资源,或使用try-with-resources
不要用异常做流程控制:异常用于处理异常情况,不要用于正常流程

小结

  • 异常是程序运行时的错误事件
  • try-catch-finally:基本异常处理结构
  • throw:主动抛出异常;throws:声明异常
  • 自定义异常:继承Exception或RuntimeException
  • 异常捕获要从小到大(子类在前)
  • 使用try-with-resources自动关闭资源
☕ Java 在线代码编辑器
📝 运行结果