所有的异常类都是Throwable类的子类,分为两个主要的子类:Exception和Error。
是指程序运行过程中可能出现的可处理的异常。它又分为两种类型:
1、非运行时异常(编译异常):需要在编译时处理的异常,即在方法声明中必须显式声明或捕获这些异常。常见的检查异常包括IOException、SQLException等。
2、运行时异常(Runtime Exception):无需在编译时处理的异常,即编译器不强制要求捕获或声明这些异常。常见的运行时异常包括NullPointerException、IllegalArgumentException等。
是指表示严重错误或不可恢复的系统错误,通常由虚拟机(JVM)抛出。一般情况下,应用程序不会捕获或处理Error,而是让它们导致程序终止。常见的Error包括OutOfMemoryError、StackOverflowError等。
throws是Java中的关键字,用于在方法声明中指定方法可能抛出的异常。当一个方法可能会引发一个或多个异常时,可以使用throws关键字将这些异常列出,以告知调用者需要处理这些异常。
使用throws关键字可以将异常向上层方法传递,直到遇到合适的异常处理机制。在方法声明中使用throws关键字后,调用该方法的代码必须在调用处处理或再次使用throws关键字传递异常。
语法:
public void myMethod() throws MyException {
// 方法体
}
throw是Java中的关键字,用于手动抛出异常对象。当在程序中遇到某个特定的条件或情况时,可以使用throw关键字创建并抛出一个异常对象,从而中断当前的执行流程,并将异常传递给上层调用栈。
使用throw关键字需要提供一个异常对象作为参数,该异常对象必须是Throwable类或其子类的实例。可以通过new关键字创建一个异常对象,并将其作为参数传递给throw关键字。
语法:
throw new MyException("异常信息");
用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
用于捕获异常。catch用来捕获try语句块中发生的异常。
finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
一个 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块中包含在无论异常是否发生时都必须执行的代码。无论异常是否被捕获或处理,finally块中的代码都会执行。可以保证资源在使用后被关闭。例如IO流中执行完相应操作后,关闭相应资源;使用Lock对象保证线程同步,通过finally可以保证锁会被释放;数据库连接代码时,关闭连接操作等等
try
块中包含可能抛出异常的代码,catch
块用于捕获和处理异常,finally
块包含在无论异常是否发生时都必须执行的代码。
try-catch-finally
的执行流程如下:
try
块中的代码会被执行。try
块中发生了异常,那么异常会被抛出,并且程序会跳转到与之匹配的catch
块进行异常处理。catch
块中的代码会根据异常类型进行相应的处理操作,如日志记录、错误处理等。try
块中没有发生异常,那么catch
块会被跳过,程序会直接执行finally
块中的代码。finally
块中的代码都会执行。通常在finally
块中放置一些必须执行的代码,如释放资源、关闭连接等。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)时,父类构造器负责初始化父类的属性,包括异常的消息、堆栈跟踪等信息。这些信息对于异常的诊断、处理和记录都是非常重要的。
在自定义异常类中,通过调用父类的构造器,可以确保父类的初始化过程得到正确执行,遵循异常处理的规范和约定。如果不调用父类构造器,可能会导致父类中的属性未正确初始化,影响异常的使用和处理。