杰瑞科技汇

java exception 定义

核心定义

在 Java 中,异常 是指程序在运行过程中出现的非正常情况错误,它是一个事件,它会中断程序正常的指令执行流程。

java exception 定义-图1
(图片来源网络,侵删)

异常就是程序运行时发生的一些“意外”或“问题”。

  • 你想让程序读取一个文件,但文件不存在。
  • 你想让程序进行除法运算,但除数是零。
  • 你想让程序访问一个数组的第 10 个元素,但数组长度只有 5。

如果没有异常处理机制,这些错误就会导致程序直接崩溃(JVM 会打印出错误堆栈信息并终止程序)。


异常的层次结构

Java 中的所有异常类都继承自 java.lang.Throwable 类。Throwable 有两个重要的子类:

  1. Error (错误):

    java exception 定义-图2
    (图片来源网络,侵删)
    • 定义: Error 类及其子类通常表示严重的、系统级别的问题,这些问题通常是不可恢复的
    • 特点:
      • 由 JVM(Java 虚拟机)或底层硬件引发。
      • 编程人员通常无法也不应该捕获和处理它们。
      • OutOfMemoryError(内存溢出)、StackOverflowError(栈溢出)、VirtualMachineError(虚拟机错误)。
    • 处理方式: 遇到 Error,程序基本只能终止,程序员需要从代码优化、系统配置等层面去解决,而不是在代码里用 try-catch 捕获。
  2. Exception (异常):

    • 定义: Exception 类及其子类表示程序本身可以处理的异常情况,这是我们日常编码中主要处理的对象。
    • 特点:
      • 可以被 try-catch 语句捕获并处理。
      • 可以被 throws 关键字声明,由上一级调用者处理。
    • Exception 又可以分为两大类:

    a. 受检异常:

    • 定义: 也叫“已检查异常”,在编译时,Java 编译器会检查是否对这类异常进行了处理(要么用 try-catch 捕获,要么用 throws 声明抛出)。

    • 目的: 强制程序员处理那些预期可能发生且可恢复的异常,提高程序的健壮性。

      java exception 定义-图3
      (图片来源网络,侵删)
    • 特点: 都是 Exception 类的子类,但不是 RuntimeException 的子类。

    • 常见例子:

      • IOException: 文件操作时可能发生的异常。
      • SQLException: 数据库操作时可能发生的异常。
      • FileNotFoundException: 文件未找到异常。
    • 示例代码:

      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      public class CheckedExceptionExample {
          public static void main(String[] args) {
              // FileNotException 是受检异常,必须处理
              try {
                  FileInputStream fis = new FileInputStream("non_existent_file.txt");
              } catch (FileNotFoundException e) {
                  System.out.println("文件未找到,请检查路径!");
                  e.printStackTrace(); // 打印异常堆栈信息
              }
              System.out.println("程序继续运行...");
          }
      }

    b. 非受检异常:

    • 定义: 也叫“未检查异常”,编译器不会检查这类异常,它们通常是程序中的逻辑错误非法操作,本应在编码时避免。
    • 目的: 提醒程序员修复代码中的潜在问题。
    • 特点: 都是 RuntimeException 类或其子类的实例。
    • 常见例子:
      • NullPointerException: 空指针异常,试图在一个 null 对象上调用方法或访问其属性。
      • ArrayIndexOutOfBoundsException: 数组下标越界异常,访问了不存在的数组索引。
      • ArithmeticException: 算术异常,整数除以零。
      • ClassCastException: 类型转换异常,将一个对象强制转换为它不是实例的子类。
    • 示例代码:
      public class UncheckedExceptionExample {
          public static void main(String[] args) {
              // ArithmeticException 是非受检异常,编译器不强制处理
              int a = 10;
              int b = 0;
              // 这行代码会抛出 ArithmeticException
              int result = a / b; // 编译时不会报错,但运行时会崩溃
              System.out.println(result);
          }
      }

异常处理机制

Java 提供了 try-catch-finallythrows 关键字来处理异常。

try-catch-finally 语句

这是最核心的异常处理方式。

  • try: 将可能抛出异常的代码块放在 try 里面。
  • catch: 捕获 try 块中发生的特定异常,并进行处理,可以有多个 catch 块来捕获不同类型的异常。
  • finally: 无论是否发生异常,finally 块中的代码一定会被执行,通常用于释放资源,如关闭文件流、数据库连接等。

语法格式:

try {
    // 可能发生异常的代码
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型的异常
} finally {
    // 无论是否发生异常,都会执行的代码(通常用于资源清理)
}

示例:

public class TryCatchExample {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        try {
            System.out.println("访问数组元素 4: " + numbers[4]); // 会抛出 ArrayIndexOutOfBoundsException
            System.out.println("这行代码不会执行");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕获到异常: 数组索引越界!");
            // e.printStackTrace(); // 打印详细的错误堆栈
        } finally {
            System.out.println("finally 块被执行,用于清理资源。");
        }
        System.out.println("程序继续运行...");
    }
}

throws 关键字

当一个方法内部处理不了某个异常时,可以使用 throws 关键字声明该方法可能会抛出的异常,将异常的处理责任交给方法的调用者

语法格式:

returnType methodName(paramList) throws ExceptionType1, ExceptionType2 {
    // 方法体,可能抛出 ExceptionType1 或 ExceptionType2
}

示例:

import java.io.IOException;
public class ThrowsExample {
    // readFile 方法声明自己可能会抛出 IOException
    public static void readFile() throws IOException {
        // 模拟文件读取失败
        throw new IOException("文件读取失败");
    }
    public static void main(String[] args) {
        try {
            readFile(); // 调用者必须处理 readFile 抛出的异常
        } catch (IOException e) {
            System.out.println("在 main 方法中捕获到异常: " + e.getMessage());
        }
        System.out.println("程序继续运行...");
    }
}

最佳实践

  1. 具体化异常: 尽量捕获具体的异常类型,而不是笼统地捕获 Exception,这样可以更精确地处理问题。

    // 不推荐
    } catch (Exception e) {
    // 推荐
    } catch (IOException e) {
    } catch (SQLException e) {
  2. 不要吃掉异常: 只捕获异常但不做任何处理(如只打印一个空日志)或 catch (Exception e) { } 是非常危险的,这会隐藏问题,导致程序在错误状态下继续运行,引发更难排查的 Bug。

  3. 使用 finallytry-with-resources 释放资源: 对于文件流、数据库连接等资源,一定要确保它们被关闭。finally 块可以保证这一点,但从 Java 7 开始,推荐使用 try-with-resources 语句,它能更优雅、更安全地自动关闭实现了 AutoCloseable 接口的资源。

    // try-with-resources (推荐)
    try (FileInputStream fis = new FileInputStream("file.txt")) {
        // 使用 fis
    } catch (IOException e) {
        e.printStackTrace();
    } // fis 会在 try 块结束后自动关闭
  4. 不要用异常来控制流程: 异常是用于处理“异常”情况的,不应该被用作常规的流程控制(用异常来处理 if-else 能判断的逻辑),这会影响性能。

特性 描述
定义 程序运行时发生的非正常事件,中断正常流程。
根类 java.lang.Throwable
两大分支 Error (系统级严重错误,不应捕获) 和 Exception (可处理的异常)
Exception 分类 受检异常 (编译器检查,必须处理) 和 非受检异常 (运行时错误,通常是代码逻辑问题)
处理方式 try-catch-finally (捕获并处理) 和 throws (声明抛出,由调用者处理)
核心目的 提高程序的健壮性容错性,使程序在出现问题时不会轻易崩溃,并能优雅地处理错误。
分享:
扫描分享到社交APP
上一篇
下一篇