Java异常处理

文章目录

  • 异常结构
    • Exception
    • Error
  • 异常关键字
    • throws
    • throw
    • try
    • catch
    • finally
  • 异常捕获
    • try-catch
    • try-finally
    • try-catch-finally
  • 自定义异常
    • 必要性
    • 自定义异常步骤

Java中的异常是指在程序执行过程中可能出现的错误或异常情况。

异常结构

所有的异常类都是Throwable类的子类,分为两个主要的子类:ExceptionError
Java异常处理_第1张图片

Exception

是指程序运行过程中可能出现的可处理的异常。它又分为两种类型:

1、非运行时异常(编译异常):需要在编译时处理的异常,即在方法声明中必须显式声明或捕获这些异常。常见的检查异常包括IOException、SQLException等。
2、运行时异常(Runtime Exception):无需在编译时处理的异常,即编译器不强制要求捕获或声明这些异常。常见的运行时异常包括NullPointerException、IllegalArgumentException等。

Error

是指表示严重错误或不可恢复的系统错误,通常由虚拟机(JVM)抛出。一般情况下,应用程序不会捕获或处理Error,而是让它们导致程序终止。常见的Error包括OutOfMemoryError、StackOverflowError等。

异常关键字

throws

throws是Java中的关键字,用于在方法声明中指定方法可能抛出的异常。当一个方法可能会引发一个或多个异常时,可以使用throws关键字将这些异常列出,以告知调用者需要处理这些异常。
使用throws关键字可以将异常向上层方法传递,直到遇到合适的异常处理机制。在方法声明中使用throws关键字后,调用该方法的代码必须在调用处处理或再次使用throws关键字传递异常
语法:

public void myMethod() throws MyException {
    // 方法体
}

throw

throw是Java中的关键字,用于手动抛出异常对象。当在程序中遇到某个特定的条件或情况时,可以使用throw关键字创建并抛出一个异常对象,从而中断当前的执行流程,并将异常传递给上层调用栈。

使用throw关键字需要提供一个异常对象作为参数,该异常对象必须是Throwable类或其子类的实例。可以通过new关键字创建一个异常对象,并将其作为参数传递给throw关键字。
语法:

throw new MyException("异常信息");

try

用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。

catch

用于捕获异常。catch用来捕获try语句块中发生的异常。

finally

finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。

异常捕获

try-catch

一个 try-catch 语句块中可以捕获多个异常类型,但只会命中匹配的第一个 catch 块,如果在try块中的代码发生了异常,程序会立即跳转到与之匹配的catch块中,并执行相应的异常处理代码,后续的 catch 块也不会再执行。
需要注意的是,try-catch块只能处理在try块中发生的异常。如果在catch块中发生新的异常,它将无法被当前的try-catch块捕获,而会被传递给上一级的异常处理机制。
语法:

try {
    // 可能抛出异常的代码
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型的异常
} catch (Exception e) {
    // 处理其他类型的异常
}

同一个 catch 也可以捕获多种类型异常,用 | 隔开,当使用|运算符将多个异常类型合并时,这些异常类型之间是平等的,没有任何继承或层级关系。在异常被捕获时,程序会检查异常对象的类型,如果异常对象的类型匹配任何一个合并的异常类型,就会执行相应的处理代码块。
语法:

try {
    // 可能抛出异常的代码
} catch (ExceptionType1 | ExceptionType2 | ExceptionType3 e) {
    // 处理 ExceptionType1、ExceptionType2 和 ExceptionType3 类型的异常
}

需要注意的是,在使用合并异常类型的catch块中,不能通过异常对象的类型来区分具体是哪种异常类型。如果需要区分异常类型进行不同的处理,应该分开编写多个catch块,每个catch块处理一个具体的异常类型。

try-finally

try块中包含可能抛出异常的代码,而finally块中包含在无论异常是否发生时都必须执行的代码。无论异常是否被捕获或处理,finally块中的代码都会执行。可以保证资源在使用后被关闭。例如IO流中执行完相应操作后,关闭相应资源;使用Lock对象保证线程同步,通过finally可以保证锁会被释放;数据库连接代码时,关闭连接操作等等

try-catch-finally

try块中包含可能抛出异常的代码,catch块用于捕获和处理异常,finally块包含在无论异常是否发生时都必须执行的代码。

try-catch-finally的执行流程如下:

  1. 首先,try块中的代码会被执行。
  2. 如果在try块中发生了异常,那么异常会被抛出,并且程序会跳转到与之匹配的catch块进行异常处理。catch块中的代码会根据异常类型进行相应的处理操作,如日志记录、错误处理等。
  3. 如果在try块中没有发生异常,那么catch块会被跳过,程序会直接执行finally块中的代码。
  4. 无论异常是否被捕获和处理,finally块中的代码都会执行。通常在finally块中放置一些必须执行的代码,如释放资源、关闭连接等。
  5. 如果在catch块中使用了return语句或抛出了新的异常,那么在执行finally块之前,先会执行return语句或抛出新异常的操作。

try-catch-finally结构提供了一种机制来处理可能发生的异常,并确保在异常处理之后执行一些必要的操作,如资源释放。它使得程序具备更好的健壮性和可靠性,可以对异常进行捕获、处理和清理工作,以保证程序的正常执行和资源的正确释放。

自定义异常

必要性

1、提供更清晰的异常信息:通过自定义异常类,可以根据实际情况为异常添加更具体的描述,帮助开发人员和调用者更好地理解异常的原因和解决方案。
2、区分不同的异常情况:自定义异常类可以根据业务需求定义不同的异常类型,从而区分不同的异常情况。这样可以使代码更具可读性和可维护性,同时也方便在异常处理时采取不同的措施。
3、异常信息传递:自定义异常类可以允许在异常对象中携带额外的信息,例如错误码、详细日志等,这些信息对于问题排查和故障诊断非常有帮助。
4、统一异常处理:通过自定义异常类,可以实现统一的异常处理机制,将不同的异常情况转换为相应的自定义异常,并在统一的异常处理模块中进行处理。这样可以提高代码的可维护性和重用性。
5、阻止未检查异常的传播:如果方法抛出的是Java标准库中的异常类(如NullPointerException、IllegalArgumentException等),则调用者可以选择忽略或不处理该异常。但通过自定义异常类,可以强制调用者必须处理或捕获该异常,以便更好地管理和处理异常情况。

自定义异常步骤

自定义异常类必须继承自现有的异常类,通常是Exception类或其子类。

自定义异常类的创建步骤如下:
1、创建一个新的类,命名为你所需的异常类型,通常以Exception结尾,例如MyException。
2、继承现有的异常类,选择合适的父类,通常是Exception类或其子类。你可以根据实际情况选择适合的父类,以便于正确地处理和捕获该异常。
3、提供构造方法,可以重载父类的构造方法,以便在抛出异常时传递相关的错误信息或其他必要的参数。
4、可以选择性地添加其他方法或属性,以满足自定义异常的特定需求。
例子:

public class MyException extends Exception {
    private int errorCode;

    public MyException (String message, int errorCode) {
        super(message);
        this.errorCode = errorCode;
    }

    public int getErrorCode() {
        return errorCode;
    }
}

在上述示例中,MyException类继承自Exception类,并添加了一个名为errorCode的私有变量。构造器接受两个参数:message和errorCode,并通过调用父类的构造器super(message)来设置异常对象的详细信息。同时,将传入的errorCode赋值给errorCode变量。
通过这样的方式,在捕获自定义异常时,可以通过调用getErrorCode()方法获取异常对象中的错误代码信息,从而更好地处理和定位异常。

在自定义异常类中调用父类构造器通常是必要的,因为父类构造器负责初始化父类的部分属性和行为,确保异常对象的完整性和一致性。

当自定义异常类继承自Java标准库中的异常类(如Exception或RuntimeException)时,父类构造器负责初始化父类的属性,包括异常的消息、堆栈跟踪等信息。这些信息对于异常的诊断、处理和记录都是非常重要的。

在自定义异常类中,通过调用父类的构造器,可以确保父类的初始化过程得到正确执行,遵循异常处理的规范和约定。如果不调用父类构造器,可能会导致父类中的属性未正确初始化,影响异常的使用和处理。

你可能感兴趣的:(java,java异常,异常处理)