我在 SO 上关注这个精彩的讨论,标题为:针对已检查异常的案例,但我无法了解应该在哪里使用 RuntimeException 以及它与普通异常及其子类有何不同。Googling 给了我一个复杂的答案,就是它应该用来处理编程逻辑错误,应该在正常情况下不应该发生异常的时候抛出,比如在 switch-case 构造的默认块中。
您能否在此处更详细地解释 RuntimeException。谢谢。
我在 SO 上关注这个精彩的讨论,标题为:针对已检查异常的案例,但我无法了解应该在哪里使用 RuntimeException 以及它与普通异常及其子类有何不同。Googling 给了我一个复杂的答案,就是它应该用来处理编程逻辑错误,应该在正常情况下不应该发生异常的时候抛出,比如在 switch-case 构造的默认块中。
您能否在此处更详细地解释 RuntimeException。谢谢。
我不知道应该在哪里使用 RuntimeException
这可能是因为您正在查看一个论点,即人们在这一点上存在分歧。
以及它与普通异常及其子类有何不同。
非常简单:检查Exception
所有子类(除了RuntimeException
及其子类),即编译器将拒绝您捕获或在方法签名中声明它们的代码。但是, 的子类是unchecked。RuntimeException
Googling 给了我一个复杂的答案,就是应该用它来处理编程逻辑错误,应该在正常不应该发生异常的时候抛出,比如在 switch-case 构造的默认块中。
这是传统观念,它说对于程序可以有效处理的所有事情,您都应该使用检查异常,因为编译器会强迫您处理它们。相反,程序通常不能有效地处理程序员错误,因此不必检查它们。这就是 Java 标准 API 使用RuntimeException
.
您链接到的讨论是由一些人(包括我)的观点引发的,他们认为检查的异常会导致错误的代码,因此不应使用。由于您无法在编译器中禁用异常检查,因此唯一的方法是仅 RuntimeException
使用及其子类。
IMO 支持这一观点的一个观察结果是,“仅对程序员错误使用未经检查的异常”的传统智慧实际上主要是向后推理的合理化:编译器不应该强迫您与程序员打交道没有代码安全理由错误。NullPointerException
然而,类似的东西ArrayIndexOutOfBoundsException
几乎可以在任何地方出现,如果这些被选中,没有人会想用 Java 编程。因此,语言设计者不得不为它们做一个,呵呵,例外,并让它们不受检查。为了解释这一点,他们提出了“未经检查的异常是针对程序员错误”的故事。
引自Effective Java 2nd Edition,第 58 条:对可恢复条件使用检查异常和对编程错误使用运行时异常
Java 编程语言提供了三种 throwable:检查异常、运行时异常和错误。程序员对于何时适合使用每种 throwable 存在一些混淆。虽然决定并不总是明确的,但有一些一般规则可以提供强有力的指导。
决定是使用已检查异常还是未检查异常的基本规则是:
- 对于可以合理预期调用者从中恢复的条件,请使用已检查异常。通过抛出已检查异常,您可以强制调用者在
catch
子句中处理异常或将其向外传播。因此,声明方法抛出的每个已检查异常都向 API 用户有力地表明相关条件是调用该方法的可能结果。- 使用运行时异常来指示编程错误。绝大多数运行时异常表明违反了先决条件。前提条件违反只是API的客户端未能遵守 API 规范指定的合同。
这是一个例子:
FileNotFoundException
是一个检查异常。null
字符串作为文件名,那么NullPointerException
(或者可能是IllegalArgumentException
另一个有争议的辩论)应该被抛出。API 的客户端应该提供一个有效的字符串值;null
不是。就 API 而言,这是一个很容易预防的程序员错误。这两个异常都是运行时异常。第 59 条:避免不必要地使用受检异常也提供了额外的指导:
检查异常是 Java 编程语言的一个很棒的特性。与返回码不同,它们迫使程序员处理异常情况,大大提高了可靠性。也就是说,过度使用检查异常会使 API 的使用变得不那么愉快。如果一个方法抛出一个或多个已检查异常,则调用该方法的代码必须在一个或多个
catch
块中处理异常,或者必须将其声明throws
为异常并让它们向外传播。无论哪种方式,它都给程序员带来了不小的负担。在以下情况下,负担是合理的:
- 不能通过正确使用 API 来防止异常情况,并且
- 一旦遇到异常,使用 API 的程序员可以采取一些有用的措施。
除非这两个条件都成立,否则未经检查的异常更合适。
下面是Effective Java 2nd Edition推荐的简短摘要:
未经检查的异常被定义为RuntimeException
及其子类Error
及其子类。它们不必在方法的throws
子句中声明。