java 异常处理机制

240 阅读6分钟

异常体系

在Java中,异常体系是以java.lang.Throwable类为根基构建的。Throwable类派生出两个重要的子类:Error和Exception,它们分别代表着错误和异常。Java的异常体系可以基于这两个子类进一步划分成多个层次结构。

image.png

图片摘自(43条消息) Java的异常处理机制_简述java中异常处理的机制?_BoSeal的博客-CSDN博客

  1. Error:
    Error表示系统内部的严重问题,大多数情况下无法恢复或处理。通常由虚拟机抛出,并且程序不应该捕获或处理这些错误。常见的Error包括OutOfMemoryError(内存不足)、StackOverflowError(栈溢出)等。

  2. Exception:
    Exception是可由程序进行捕获和处理的异常类型。它又分为两类:可检查异常(Checked Exceptions)和不可检查异常(Unchecked Exceptions)。

    a. 可检查异常(Checked Exceptions):
    可检查异常是在代码编译时由编译器强制要求处理的异常。开发人员必须在代码中捕获或声明可能抛出这些异常的方法。常见的可检查异常包括IOException、SQLException、ClassNotFoundException等。

    b. 不可检查异常(Unchecked Exceptions):
    不可检查异常是在运行时由Java虚拟机自动抛出的异常。它们通常表示程序本身的错误或其他无法恢复的异常情况。开发人员虽然可以使用try-catch块来捕获并处理这些异常,但通常更重要的是通过编写健壮的代码来避免它们的发生。不可检查异常包括NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException、ArithmeticException等。

异常体系的结构如下所示:

java.lang.Throwable
├── java.lang.Error
│   ├── java.lang.AssertionError
│   ├── java.lang.VirtualMachineError
│   │   ├── java.lang.OutOfMemoryError
│   │   ├── java.lang.StackOverflowError
│   │   └── ...
│   └── ...
│
└── java.lang.Exception
    ├── java.lang.RuntimeException
    │   ├── java.lang.NullPointerException
    │   ├── java.lang.ArrayIndexOutOfBoundsException
    │   ├── java.lang.ClassCastException
    │   ├── java.lang.ArithmeticException
    │   └── ...
    └── ...

异常处理

在Java中异常处理机制主要是 抛出异常,捕获异常,处理异常

throw关键字

throw关键字用于手动引发异常。它通常与try-catch或throws语句结合使用。通过使用throw关键字,你可以在程序中显式地触发异常,以便在程序的某个地方处理它。

下面是throw关键字的用法示例:

throw new ExceptionType("Error message");

**

在上面的示例中,ExceptionType是异常的类型,可以是Java提供的内置异常类,也可以是自定义的异常类。"Error message"是异常的详细描述。

使用throw关键字,你可以在程序的任何地方抛出异常,使得异常被传递到相应的异常处理代码块中。如果没有适当的异常处理代码,该异常将会被传递至调用栈的上一级,直到找到合适的异常处理。

下面是一个示例,演示了在Java中如何使用throw关键字抛出异常:

public class Example {
    public static void main(String[] args) {
        try {
            divide(10, 0);
        } catch (ArithmeticException e) {
            System.out.println("Exception caught: " + e.getMessage());
        }
    }
    
    public static int divide(int num1, int num2) throws ArithmeticException {
        if (num2 == 0) {
            throw new ArithmeticException("Division by zero is not allowed!");
        }
        return num1 / num2;
    }
}

**

在上面的示例中,divide方法通过使用throw关键字,在遇到除数为0的情况时,抛出了一个自定义的ArithmeticException异常。在main方法中,我们使用try-catch块来捕获并处理这个异常。

当运行上面的代码时,由于除以0是不允许的,将会抛出一个ArithmeticException异常,并在catch块中打印异常信息。

throws关键字

在Java中,throws关键字用于在方法签名中声明该方法可能抛出的异常类型。它往往与方法声明一起使用,用于指示该方法可能会引发某种类型的异常,并将这个责任转移到方法的调用方。

使用throws关键字可以在方法声明中指定一个或多个异常类型,如下所示:

modifier returnType methodName(parameters) throws ExceptionType1, ExceptionType2, ... {
    // 方法体
}

**

在上述方法声明中,ExceptionType1、ExceptionType2等是方法可能抛出的异常类型。当方法内部可能会发生这些异常时,可以使用throws关键字声明它们。

声明方法抛出异常时,它意味着方法并不会处理这些异常,而是将它们传递给方法的调用方。调用方必须使用try-catch块来捕获这些异常,或者将异常继续向上层抛出。

以下是一个使用throws关键字的示例:

public class Example {
    public static void main(String[] args) {
        try {
            performDangerousOperation();
        } catch (Exception e) {
            System.out.println("Exception caught: " + e.getMessage());
        }
    }
    
    public static void performDangerousOperation() throws Exception {
        // code that may throw an exception
        throw new Exception("Dangerous operation encountered");
    }
}

**

在上述示例中,performDangerousOperation()方法使用throws关键字声明可能抛出Exception类型的异常。在performDangerousOperation()方法内部,我们通过throw关键字手动抛出一个Exception异常。

在main方法中,我们调用performDangerousOperation()方法,并使用try-catch块捕获并处理异常。因为performDangerousOperation()方法声明了throws Exception,调用方必须处理这个异常或将其继续向上层抛出。

但是要注意的是,throws关键字只是一个方法声明时的说明,它并不会实际引发异常。异常的引发是通过throw关键字来实现的。throws关键字只是告诉调用方:调用这个方法时需要注意处理可能的异常。

try catch finally

在Java中,try-catch-finally是一组关键字,用于异常处理和资源的清理。这个组合可以用来有效地捕获异常并确保在异常处理之后执行必要的清理操作。

try块用于包含可能抛出异常的代码。在try块中,如果发生异常,程序将会立即跳转到相应的catch块进行异常处理。

catch块用于捕获并处理指定类型的异常。在catch块中,你可以指定捕获的异常类型,并提供相应的处理逻辑。一个try块可以有多个catch块,用于捕获不同类型的异常。

finally块是可选的,用于包含无论是否发生异常都必须执行的代码。无论异常是否被捕获或处理,finally块中的代码都将执行,一般用于释放资源,比如文件关闭

下面是try-catch-finally关键字的用法示例:

try {
    // 可能抛出异常的代码
} catch (ExceptionType1 e1) {
    // 处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
    // 处理ExceptionType2类型的异常
} finally {
    // 执行清理操作,无论异常是否发生都会执行
}

**

在上面的示例中,try块包含可能抛出异常的代码。如果发生异常,程序将跳转到相应的catch块进行异常处理。根据异常类型的匹配,将选择执行相应的catch块。最后,不管是否发生异常,finally块中的代码都会执行。

以下是一个示例,演示了try-catch-finally关键字的使用:

public class Example {
    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("Exception caught: " + e.getMessage());
        } finally {
            System.out.println("Finally block executed");
        }
    }
    
    public static int divide(int num1, int num2) throws ArithmeticException {
        if (num2 == 0) {
            throw new ArithmeticException("Division by zero is not allowed!");
        }
        return num1 / num2;
    }
}

**

在上面的示例中,我们在divide方法中使用throw关键字手动抛出ArithmeticException异常。在main方法中,我们用try-catch块捕获并处理这个异常。无论是否发生异常,finally块中的代码都会执行,用于执行一些清理操作。

当运行上面的代码时,由于除以0是不允许的,将会抛出一个ArithmeticException异常,并在catch块中打印异常信息。无论是否发生异常,finally块中的代码都会执行,在控制台显示"Finally block executed"的输出。