异常处理是 Java 编程中不可或缺的一部分,它帮助开发者优雅地处理程序运行时的错误情况,避免程序直接崩溃。以下是 Java 异常处理的核心内容:


异常体系结构

Java 的异常体系以 java.lang.Throwable 为根类,分为两大分支:

  • Exception:程序可处理的异常,包括受检异常(Checked Exception)和非受检异常(Unchecked Exception)。
  • Error:程序无法处理的严重问题,通常与 JVM 或系统资源相关。
Throwable
├── Error
│   ├── StackOverflowError
│   ├── OutOfMemoryError
│   └── ...
└── Exception
    ├── RuntimeException
    │   ├── NullPointerException
    │   ├── ArrayIndexOutOfBoundsException
    │   └── ...
    └── 其他受检异常
        ├── IOException
        ├── FileNotFoundException
        └── ...


Exception 与 Error 的区别

Exception
  • 程序可以处理的异常。
  • 通过 try-catchthrows 机制处理。
  • 示例:文件不存在、空指针、数组越界等。
Error
  • 程序无法处理的严重问题。
  • 通常由 JVM 或系统资源问题引起。
  • 示例:StackOverflowErrorOutOfMemoryError
  • 不建议捕获 Error,应优化代码逻辑避免。
public class ErrorDemo {
    public static void recursiveMethod() {
        recursiveMethod(); // 无限递归导致 StackOverflowError
    }

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


运行时异常与非运行时异常

运行时异常(RuntimeException)
  • 继承自 RuntimeException
  • 编译器不强制处理。
  • 示例:NullPointerExceptionArrayIndexOutOfBoundsException
  • 通常通过改进代码逻辑避免。
public class NullPointerDemo {
    public static void main(String[] args) {
        String str = null;
        System.out.println(str.length()); // NullPointerException
    }
}

非运行时异常(Checked Exception)
  • 不继承 RuntimeException
  • 编译器强制处理(捕获或声明抛出)。
  • 示例:IOExceptionSQLException
import java.io.*;

public class CheckedExceptionDemo {
    public static void main(String[] args) {
        try {
            FileReader fr = new FileReader("nonexistent.txt");
        } catch (FileNotFoundException e) {
            System.out.println("文件未找到: " + e.getMessage());
        }
    }
}


异常处理机制

try-catch-finally
  • 直接捕获并处理异常。
  • finally 块用于释放资源。
public class TryCatchDemo {
    public static void main(String[] args) {
        try {
            int a = 10 / 0; // ArithmeticException
        } catch (ArithmeticException e) {
            System.out.println("捕获到算术异常: " + e.getMessage());
        } finally {
            System.out.println("执行 finally 块");
        }
    }
}

throws
  • 将异常抛给调用者处理。
  • 适用于不适合在当前方法中处理异常的情况。
public class ThrowsDemo {
    public static void readFile() throws FileNotFoundException {
        FileReader fr = new FileReader("nonexistent.txt");
    }

    public static void main(String[] args) {
        try {
            readFile();
        } catch (FileNotFoundException e) {
            System.out.println("处理文件未找到异常");
        }
    }
}


多级 catch

  • 捕获多种异常时,子类异常应放在父类异常之前。
public class MultiCatchDemo {
    public static void main(String[] args) {
        try {
            int[] array = new int[3];
            array[5] = 10; // ArrayIndexOutOfBoundsException
            String s = null;
            s.length();    // NullPointerException
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界: " + e);
        } catch (NullPointerException e) {
            System.out.println("空指针: " + e);
        } catch (Exception e) {
            System.out.println("其他异常: " + e);
        }
    }
}

多异常捕获语法

从 Java 7 开始支持在单个 catch 块中捕获多个异常类型,使用竖线 | 分隔异常类型。这种语法适用于处理逻辑相同的异常场景。

try {
    // 可能抛出多种异常的代码
} catch (ArrayIndexOutOfBoundsException | NullPointerException e) {
    System.out.println("发生数组越界或空指针异常");
}

finally 块特性

finally 块确保资源释放的执行可靠性,其特点包括:

  • 无论是否发生异常都会执行
  • 即使 try 或 catch 块中有 return 语句也会执行
  • 主要应用于资源清理场景
FileInputStream fis = null;
try {
    fis = new FileInputStream("file.txt");
    // 文件操作代码
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

try-with-resources 机制

Java 7 引入的自动资源管理语法要求:

  • 资源必须实现 AutoCloseable 接口
  • 资源声明写在 try 后的括号内
  • 退出 try 块后自动调用 close() 方法
try (FileReader reader = new FileReader("test.txt");
     BufferedReader br = new BufferedReader(reader)) {
    String line = br.readLine();
} catch (IOException e) {
    e.printStackTrace();
}

throws 声明规范

方法抛出异常时的处理原则:

  • 受检异常必须显式声明
  • 运行时异常可省略 throws 声明
  • 调用声明 throws 的方法必须处理异常
public void readConfig() throws FileNotFoundException {
    // 不处理异常直接抛出
    new FileInputStream("config.ini");
}

自定义异常实现

创建自定义异常需注意:

  • 业务异常建议继承 Exception
  • 非强制处理异常继承 RuntimeException
  • 应提供包含错误信息的构造方法
class PaymentException extends Exception {
    public PaymentException(String message) {
        super(message);
    }
    
    public PaymentException(String message, Throwable cause) {
        super(message, cause);
    }
}

异常处理最佳实践

  1. 避免捕获过于宽泛的异常类型
  2. 不要用异常替代正常流程控制
  3. 确保资源释放使用 try-with-resources
  4. 记录异常日志时包含完整堆栈信息
  5. 保持异常信息对调试有帮助
// 不良实践示例
try {
    // 业务代码
} catch (Exception e) {
    // 空的catch块
}

// 推荐做法
try {
    // 业务代码
} catch (SpecificException e) {
    logger.error("操作失败,参数: {}", param, e);
    throw new BusinessException("操作失败", e);
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐