Skip to main content

第八课:异常处理

异常是程序运行过程中出现的错误情况,Java 提供强大的异常处理机制来应对这些情况,确保程序的稳定性和可用性。

  • 异常 vs 错误
    1. 错误(Error):无法恢复的严重问题,通常由 JVM 抛出。例如内存溢出 (OutOfMemoryError)。
    2. 异常(Exception):程序可以处理的问题。

(一)Java 中的异常分类

1. 检查性异常

  • 用户引起的错误,编译时必须被处理。
  • 例如:IOException, SQLException
  • 特性
    • 必须通过 try-catch 捕获或使用 throws 声明处理。
  • 示例:
    try {
        BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    

2. 运行时异常

  • 程序中的逻辑错误,编译时不强制处理。
  • 属于 RuntimeException 类的子类,例如:NullPointerException, ArrayIndexOutOfBoundsException
  • 特性
    • 运行时才出现。
    • 开发中应尽量避免。
  • 示例:
    String str = null;
    System.out.println(str.length()); // 抛出 NullPointerException
    

3. 错误 (Error)

  • JVM 抛出的严重问题,比如内存不足、栈溢出。
  • 程序通常无法恢复。如:OutOfMemoryError, StackOverflowError

(二)Java 异常处理的关键字

1. try-catch

  • 包裹可能抛出异常的代码。
  • 捕获并处理异常。
  • 语法:
    try {
        // 有可能抛出异常的代码
    } catch (ExceptionType e) {
        // 异常的处理代码
    }
    
  • 示例
    try {
        int result = 10 / 0; // 此处抛出 ArithmeticException
    } catch (ArithmeticException e) {
        System.out.println("错误:" + e.getMessage());
    }
    

2. finally

  • 用于清理资源,无论是否发生异常都会执行。

  • 通常用于关闭文件、释放数据库连接等。

  • 语法

    try {
        // 有可能抛出异常的代码
    } catch (ExceptionType e) {
        // 异常的处理代码
    } finally {
        // 始终会执行的代码
    }
    
  • 示例

    try {
        int[] arr = new int[2];
        System.out.println(arr[3]); // ArrayIndexOutOfBoundsException
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("数组越界异常:" + e.getMessage());
    } finally {
        System.out.println("关闭资源");
    }
    

3. throw

  • 用于手动抛出一个异常。
  • 通常用于验证条件不满足时抛出异常。
  • 语法
    if (condition) {
        throw new ExceptionType("异常信息");
    }
    
  • 示例
    public void checkAge(int age) {
        if (age < 18) {
            throw new IllegalArgumentException("年龄必须大于或等于 18");
        }
    }
    

4. throws

  • 用于声明方法可能抛出的异常,由调用者处理。
  • 语法
    public void readFile() throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("test.txt"));
    }
    
  • 示例
    public static void main(String[] args) throws IOException {
        readFile();
    }
    
    public static void readFile() throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("test.txt"));
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }
    

(三)Java 内置异常类

Java 在 java.lang 包中定义了一些常见的异常类:

1. 运行时异常类

异常类型描述
ArithmeticException数学运算异常,例如 除以零
ArrayIndexOutOfBoundsException数组下标越界。
ClassCastException对象不能强制转换为子类。
IllegalArgumentException方法传递了非法参数。
NullPointerException试图访问 null 对象的成员或方法时抛出。
NumberFormatException试图将字符串解析为数字格式失败。

2. 检查性异常类

异常类型描述
IOException输入/输出操作失败。
FileNotFoundException文件未找到。
SQLException数据库操作失败。
ClassNotFoundException当加载一个不存在的类时抛出。
InterruptedException线程中断时抛出。

(四)捕获多个异常

一个 try 块可以跟多个 catch 块;当发生异常时,会按顺序检查每个 catch 块。

语法

try {
    // 代码
} catch (ExceptionType1 e1) {
    // 捕获异常类型1
} catch (ExceptionType2 e2) {
    // 捕获异常类型2
}

示例

try {
    int[] arr = new int[2];
    System.out.println(arr[3]); // 数组越界
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("数组越界异常");
} catch (NullPointerException e) {
    System.out.println("空指针异常");
}

(五)自动关闭资源

JDK 7 后新增,用于自动关闭实现了 AutoCloseable 接口的资源(如文件流、数据库连接)。

优点:不需要显式关闭资源(如 close())。

语法

try (资源声明) {
    // 使用资源的代码
} catch (Exception e) {
    // 异常捕获代码
}

示例

import java.io.*;

public class TryWithResourcesExample {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("文件读取错误:" + e.getMessage());
        }
    }
}

(六)创建自定义异常

自定义异常类继承 ExceptionRuntimeException 类。

步骤

  1. 定义一个自定义异常类。
  2. 在需要的地方通过 throw 抛出异常。

示例

// 自定义异常类
class InvalidAgeException extends Exception {
    public InvalidAgeException(String message) {
        super(message); // 调用父类构造器
    }
}

// 使用自定义异常
public class CustomExceptionExample {
    public void checkAge(int age) throws InvalidAgeException {
        if (age < 18) {
            throw new InvalidAgeException("年龄必须 >= 18");
        }
    }

    public static void main(String[] args) {
        CustomExceptionExample example = new CustomExceptionExample();
        try {
            example.checkAge(16); // 抛出异常
        } catch (InvalidAgeException e) {
            System.out.println("异常:" + e.getMessage());
        }
    }
}

输出

异常:年龄必须 >= 18