39

如果我没记错的话,应该首先捕获异常的子类。但是必须捕获任何 RuntimeException 和一个具体的检查异常,首先应该捕获它们?

try {
    ...
} catch(RuntimeException e) {
    ...
} catch(IOException e) {
    ...
}

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

4

3 回答 3

72

顺序是首先匹配的,然后执行正如 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();
}

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

您的情况是正确的,因为 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();
}

所以,你应该先有孩子,然后才有父母例外。

于 2012-06-09T22:00:41.090 回答
4

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

两者都不。正如其他答案所说,编译器应该告诉您是否将简单的捕获按顺序排列,其中一个捕获另一个。

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

使用catch记录诊断作为紧急关闭的一部分是可以的,但是如果您捕获并尝试从中恢复 RuntimeException,则需要注意不要在地毯下扫除严重的问题:

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

  • 考虑尝试恢复是否明智。如果你有一个未知的错误,它可能会在触发异常之前造成不可预知的损害。您无法知道应用程序是否可以恢复,或者它是否会因尝试继续而造成更严重的损害。

同样的建议也适用于 catchExceptionThrowable/ Error。由于很可能已经发生的损害的性质,它对Throwable/更为关键。Error

于 2012-06-10T03:10:54.460 回答
0

编译器将接受的任何顺序都是正确的。

于 2012-06-09T22:00:12.307 回答