如果我没有弄错的话,应首先捕获异常的子类。但是必须捕获任何RuntimeException和一个具体检查的Exception,它应该首先被捕获?
try {
...
} catch(RuntimeException e) {
...
} catch(IOException e) {
...
}
这个订单是正确的吗?或者它是正确的但是一个糟糕的选择?
答案 0 :(得分:59)
订单首先匹配,执行(as the JLS clearly explains)。
如果第一个catch匹配异常,则执行,如果不匹配,则执行下一个异常,直到一个匹配或没有匹配。
因此,在捕获异常时,您希望始终首先捕获最具体的,然后是最通用的(如RuntimeException或Exception)。例如,假设您希望捕获StringIndexOutOfBoundsException方法引发的 String.charAt(index) ,但您的代码也可以抛出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 它进入第一个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();
}
因此,您应首先拥有孩子,然后是父异常。
答案 1 :(得分:4)
这个订单是正确的吗?或者它是正确的但是一个糟糕的选择?
都不是。正如其他答案所述,编译器应该告诉您是否将简单捕获按照一个掩盖另一个的顺序。
但是您的代码中还有另一个潜在的问题:您是否真的要抓住RuntimeException
。问题是有许多未经检查的异常的来源/原因,其中许多来源/原因实际上是您的应用程序中的错误。
使用catch
将诊断记录为紧急关闭的一部分很好,但是
如果你抓住并试图从 RuntimeException
恢复,你需要小心,你没有在地毯下扫除一个严重的问题:
确保您记录异常及其堆栈跟踪,无论如何。
考虑是否明智尝试恢复。如果你有一个未知的bug,它可能会在触发异常之前造成不可预测的损害。您无法知道应用程序是否可以恢复,或者是否可能通过继续尝试来造成更严重的损害。
同样的建议适用于抓取Exception
和Throwable
/ Error
。对Throwable
/ Error
更为重要,因为可能已经发生的损害的性质。
答案 2 :(得分:1)
编译器接受的任何顺序都是正确的。