在Java中捕获exception的顺序

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

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

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

顺序是先匹配,执行 ( 如JLS清楚解释 )。

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

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

 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(); } 

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

您的情况是正确的,因为IOExceptioninheritance自Exception,RuntimeException也inheritance自Exception,因此它们不会相互跳过。

这也是一个编译错误,首先捕获一个通用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(); } 

所以,你应该首先拥有孩子,然后是父exception。

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

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

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

使用catch来记录诊断作为紧急关闭的一部分很好,但是如果你抓住并试图从 RuntimeException 恢复 ,你需要小心你没有在地毯下扫除一个严重的问题:

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

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

同样的建议适用于捕获ExceptionThrowable / Error 。 由于可能已经发生的损坏的性质,它对Throwable / Error更为关键。

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