在Java中捕获异常的顺序

Joh*_*Doe 33 java exception

如果我没有弄错,应首先捕获异常的子类.但是必须捕获任何RuntimeException和具体检查的Exception,它应该首先被捕获?

try {
    ...
} catch(RuntimeException e) {
    ...
} catch(IOException e) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

这个订单是正确的吗?或者它是正确的但是一个糟糕的选择?

Mau*_*res 62

订单是先匹配,执行(如JLS清楚解释).

如果第一个catch匹配异常,则执行,如果不匹配,则执行下一个异常,直到一个匹配或者没有匹配.

因此,在捕获异常时,您希望始终首先捕获最具体的异常,然后捕获最通用的异常(如RuntimeException或Exception).例如,假设您想要捕获String.charAt(index)方法抛出的StringIndexOutOfBoundsException,但您的代码也可能抛出NullPointerException,以下是您可以捕获异常的方法:

String s = null;
try {
  s.charAt(10);
} catch ( NullPointerExeption e ) {
  System.out.println("null");
  e.printStackTrace();
} catch ( StringIndexOutOfBoundsException e ) {
  System.out.println("String index error!");
  e.printStackTrace();
} catch ( RuntimeException e ) {
  System.out.println("runtime exception!");
  e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

所以,通过这个顺序,我确保异常被正确捕获并且它们不会互相绊倒,如果它是NullPointerException它进入第一个catch,如果它进入第二个StringIndexOutOfBoundsException,最后如果它是其他东西是一个RuntimeException(或从它继承,就像IllegalArgumentException一样)它进入第三个catch.

您的情况是正确的,因为IOException继承自Exception,RuntimeException也继承自Exception,因此它们不会相互跳过.

这也是一个编译错误,首先捕获一个通用异常,然后再捕获其中一个后代,如:

try {
  // some code here
} catch ( Exception e) {
  e.printStackTrace();
} catch ( RuntimeException e ) { // this line will cause a compilation error because it would never be executed since the first catch would pick the exception
  e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

所以,你应该首先拥有孩子,然后是父异常.


Ste*_*n C 5

这个顺序正确吗?或者它是正确的但却是一个糟糕的选择?

两者都不。正如其他答案所说,编译器应该告诉您是否按照一个掩盖另一个的顺序放置简单的捕获。

但是您的代码中还有另一个潜在问题:您是否真的应该捕获RuntimeException吗?问题是,未经检查的异常有许多潜在的来源/原因,其中许多来源/原因实际上是应用程序中的错误。

使用catch来记录诊断作为紧急关闭的一部分是可以的,但是如果您捕获并尝试从中恢复RuntimeException,则需要小心,不要将严重的问题掩盖起来:

  • 无论如何,请确保记录异常及其堆栈跟踪。

  • 考虑尝试恢复是否明智。如果您遇到未知错误,它可能在触发异常之前就已造成损坏(例如,对重要数据结构)。一般来说,您无法知道应用程序是否可以恢复,或者尝试恢复是否会造成更严重的损害。

同样的建议适用于 catchExceptionThrowable/ Error。由于损害的性质很可能已经发生,因此Throwable/更为重要。Error