catch块内抛出的exception – 它会再次被捕获吗?

这可能看起来像一个编程101的问题,我以为我知道答案,但现在发现自己需要仔细检查。 在下面这段代码中,第一个catch块中抛出的exception会被下面的一般Exception catch块捕获吗?

try { // Do something } catch(IOException e) { throw new ApplicationException("Problem connecting to server"); } catch(Exception e) { // Will the ApplicationException be caught here? } 

我一直认为答案是否定的,但现在我有一些奇怪的行为,可能是由此造成的。 对于大多数语言来说,答案可能是相同的,但是我正在使用Java。

不,因为新的throw不直接在try块中。

不,这很容易检查。

 public class Catch { public static void main(String[] args) { try { throw new java.io.IOException(); } catch (java.io.IOException exc) { System.err.println("In catch IOException: "+exc.getClass()); throw new RuntimeException(); } catch (Exception exc) { System.err.println("In catch Exception: "+exc.getClass()); } finally { System.err.println("In finally"); } } } 

应该打印:

在捕获IOException中:类java.io.IOException
终于
线程“main”java.lang.RuntimeException中的exception
        在Catch.main(Catch.java:8) 

从技术上讲,这可能是一个编译器错误,依赖于实现,未指定的行为,或者其他。 然而,JLS已经被很好的钉住了,编译器对于这种简单的事情来说足够好了(generics的情况可能是另一回事)。

另外请注意,如果你交换两个catch块,它不会编译。 第二个捕获将是完全无法达到的。

请注意,即使执行catch块,finally块也会一直运行(除了无用循环之外,通过工具接口附加和杀死线程,重写字节码等)。

Java语言规范在14.19.1节中提到:

如果try块的执行由于抛出一个值V而突然完成,那么就有一个select:

  • 如果V的运行时types可分配给try语句的任何catch子句的Parameter,则select第一个(最左边的)这样的catch子句。 值V被分配给所选的catch子句的参数,并且该catch子句的Block被执行。 如果该块正常完成,则try语句正常结束; 如果该块由于某种原因突然完成,则由于相同的原因,try语句突然完成。

参考: http : //java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134

换句话说,第一个可以处理exception的封闭的catch函数会产生exception,如果抛出的exception不在原始try的任何其他catch的范围内,所以他们不会去处理它。

一个相关而令人困惑的事情是,在try-catch结构中finally块可能会抛出一个exception,如果是这样的话try或catch块抛出的任何exception都会丢失。 这可能会让你第一次看到它。

如果你想从catch块中抛出exception,你必须通知你的方法/类/ etc。 它需要抛出exception。 像这样:

 public void doStuff() throws MyException { try { //Stuff } catch(StuffException e) { throw new MyException(); } } 

现在你的编译器不会嚷嚷你:)

不 – 正如Chris Jester-Young所说,它会被抛到层次结构中的下一个尝试。

如上所述…
我会补充一点,如果你看不清楚发生了什么,如果你不能在debugging器中重现这个问题,你可以在重新抛出新exception之前添加一个跟踪(旧的System.out.println更糟糕,如log4j一样好的日志系统)。

它不会被第二个catch块捕获。 每个exception仅在try块内被捕获。 你可以尝试嵌套尝试(不是说这是一个好主意):

 try { doSomething(); } catch (IOException) { try { doSomething(); } catch (IOException e) { throw new ApplicationException("Failed twice at doSomething" + e.toString()); } } catch (Exception e) { } 

不,因为捕获都是指同一个try块,所以从catch块中抛出将被一个封闭的try块捕获(可能在调用这个块的方法中)

旧post但“e”variables必须是唯一的:

 try { // Do something } catch(IOException ioE) { throw new ApplicationException("Problem connecting to server"); } catch(Exception e) { // Will the ApplicationException be caught here? }