思维导图:
5.5 自定义异常类
为什么需要自定义异常类:
- Java内置的异常类不足以覆盖所有特定的业务场景。
- 特定情况需要特定的异常描述,比如除数为负的情况。
自定义异常的步骤:
-
创建异常类:
- 继承自
Exception
类或其子类。 - 提供无参和有参构造器,有参构造器可以接收错误消息等参数。
- 继承自
-
抛出异常:
- 使用
throw
关键字在方法中抛出新的异常实例。 - 示例:
throw new DivideByMinusException("除数是负数");
- 使用
-
异常声明:
- 在方法签名中使用
throws
关键字声明方法可能抛出的异常。 - 例子:
public static int divide(int x, int y) throws DivideByMinusException
- 在方法签名中使用
异常的处理:
- 使用
try...catch
语句块捕获和处理异常。 - 在
catch
块中打印异常信息或进行其他异常处理。
示例代码解读:
class DivideByMinusException extends Exception {
// 调用Exception类的无参构造方法
public DivideByMinusException() {
super();
}
// 调用Exception类的有参构造方法,传递错误信息
public DivideByMinusException(String message) {
super(message);
}
}
public class Example09 {
public static void main(String[] args) {
try {
int result = divide(4, -2);
System.out.println(result);
} catch (DivideByMinusException e) {
// 打印异常信息
System.out.println(e.getMessage());
}
}
// 使用throws关键字声明可能抛出DivideByMinusException异常
public static int divide(int x, int y) throws DivideByMinusException {
if (y < 0) {
// 当除数为负数时抛出自定义异常
throw new DivideByMinusException("除数是负数");
}
// 计算结果并返回
return x / y;
}
}
注意事项:
- 自定义异常类名应该清晰表达异常情况。
- 自定义异常应当在逻辑上为检查型异常,即继承
Exception
。 - 抛出自定义异常时,不要忘记在方法签名中声明。
错误处理和编译器错误:
- 必须处理或声明所有的检查型异常,否则编译器将报错。
- 如果方法内部抛出异常(不是运行时异常),该方法必须声明
throws
或捕获异常。
调试和错误信息:
- 通过异常的错误消息可以快速定位和理解异常产生的背景。
- 捕获异常后,可以选择打印异常堆栈(
e.printStackTrace()
)来获得更详细的错误信息。
我的理解:
这一节讲述了Java中自定义异常类的概念和如何使用它们。要理解这一节,我们需要先明白异常(Exception)在Java编程中的作用。异常是程序运行过程中发生的不正常情况,Java内置了很多异常类来表示各种可能出现的错误。然而,这些内置的异常类不总能精确地描述所有可能出现的问题,特别是那些业务逻辑相关的特殊情况。
自定义异常类允许程序员创建专门的异常来表示程序中的特定错误。下面是理解这一节概念的关键点:
-
何时需要自定义异常:
- 当内置的异常类无法充分表示程序中遇到的特定问题时。
- 当你想提供更详细的异常信息给方法的调用者时。
- 当你需要区分应用中的不同错误类型,进行特殊的错误处理时。
-
自定义异常的要求:
- 自定义异常必须继承自Java的
Exception
类(或其子类),这是因为只有Throwable
的子类才能被Java虚拟机抛出和处理。 - 通常,自定义异常会提供两个构造方法:一个无参构造方法和一个带有详细错误信息的构造方法。
- 自定义异常必须继承自Java的
-
抛出自定义异常:
- 使用
throw
关键字可以在代码中的任何位置创建并抛出异常对象。 - 抛出异常后,程序控制流将被转移到最近的异常处理器(即
catch
块),如果没有合适的处理器,程序将终止。
- 使用
-
声明异常:
- 如果一个方法可能会抛出某个异常,但不打算立即处理它,那么该方法必须通过
throws
关键字在其声明中指明可能抛出的异常类型。 - 这告诉方法的调用者需要处理或进一步声明这个异常。
- 如果一个方法可能会抛出某个异常,但不打算立即处理它,那么该方法必须通过
-
异常处理:
- 通过
try...catch
语句块,你可以捕获并处理特定类型的异常。 - 在
catch
块中,通常会记录异常信息、终止操作或者尝试恢复程序状态。
- 通过
通过以上的步骤,你可以在你的应用中实现精细化的错误管理,创建更加健壮和可维护的代码。自定义异常是Java异常处理策略中的一个高级特性,能够提升程序的安全性和可读性。
总结:
重点:
-
继承Exception类:自定义异常必须继承自
Exception
类(或者RuntimeException
类),以确保它具有异常的所有基本属性和行为。 -
构造方法:自定义异常类通常需要至少提供两种构造器:无参构造器和带消息参数的构造器。无参构造器允许简单地抛出异常,带消息的构造器则允许抛出包含详细描述信息的异常。
-
使用
throw
关键字:通过使用throw
关键字手动抛出异常实例。 -
使用
throws
关键字声明异常:在方法签名中使用throws
声明该方法可能抛出的异常,告知方法调用者需要对这些异常进行处理。
难点:
-
何时创建自定义异常:确定在什么情况下需要创建自定义异常类,而不是使用现有的Java标准异常类。
-
异常链:在自定义异常中包含原始异常信息(通过调用
initCause
方法或提供一个接收Throwable
参数的构造器),以保留异常链,这对于调试非常重要,但容易被忽略。
易错点:
-
遗漏
throws
声明:在使用自定义异常的方法中遗漏throws
声明,导致编译错误。 -
异常处理不完整:在
catch
块中不完整的处理自定义异常,可能会导致程序中断或处于不稳定状态。 -
滥用自定义异常:创建不必要的自定义异常类,使得异常体系过于复杂,增加了代码的维护难度。
-
异常信息不明确:在创建异常实例时,未提供足够明确的错误信息,这会使得最终的异常处理更加困难。
-
不恰当的继承:错误地将自定义异常继承自
RuntimeException
可能导致未被捕获的运行时异常,而应当根据异常的检查性(checked)或非检查性(unchecked)来决定继承自Exception
还是RuntimeException
。
总结来说,创建自定义异常类时需要注意继承、构造方法的实现,以及在可能抛出异常的方法中使用 throws
关键字进行声明,并在调用这些方法的地方妥善处理异常。同时,应该避免创建不必要的自定义异常类,只有当标准异常类不足以表达特定错误情况时,才创建自定义异常。