Exception thrown inside catch block - will it be caught again?
这可能看起来像编程101问题,我原以为我知道答案,但现在发现自己需要仔细检查。 在下面的这段代码中,第一个catch块中抛出的异常是否会被下面的常规异常捕获块捕获?
1 2 3 4 5 6 7 | try { // Do something } catch(IOException e) { throw new ApplicationException("Problem connecting to server"); } catch(Exception e) { // Will the ApplicationException be caught here? } |
我一直认为答案是否定的,但现在我有一些可能由此造成的奇怪行为。 答案可能与大多数语言相同,但我在Java工作。
不,因为新的
不,这很容易检查。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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"); } } } |
应打印:
1 2 3 4 | In catch IOException: class java.io.IOException In finally Exception in thread"main" java.lang.RuntimeException at Catch.main(Catch.java:8) |
从技术上讲,这可能是编译器错误,依赖于实现,未指定的行为或其他东西。然而,JLS已经很好地确定了,并且编译器对于这种简单的事情已经足够好了(泛型角落情况可能是另一回事)。
还要注意,如果你交换两个catch块,它就不会编译。第二次捕获将完全无法到达。
注意,即使执行了一个catch块,finally块也会一直运行(除了愚蠢的情况,例如无限循环,通过工具接口附加并杀死线程,重写字节码等)。
Java语言规范在第14.19.1节中说:
If execution of the try block completes abruptly because of a throw of a value V, then there is a choice:
- If the run-time type of V is assignable to the Parameter of any catch clause of the try statement, then the first (leftmost) such catch clause is selected. The value V is assigned to the parameter of the selected catch clause, and the Block of that catch clause is executed. If that block completes normally, then the try statement completes normally; if that block completes abruptly for any reason, then the try statement completes abruptly for the same reason.
参考:
http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134
换句话说,可以处理异常的第一个封闭catch,如果从该catch中抛出异常,那么它不在原始try的任何其他catch的范围内,因此它们不会尝试处理它。
一个相关且令人困惑的事情是,在try- [catch] -finally结构中,finally块可能抛出异常,如果是这样,try或catch块抛出的任何异常都会丢失。第一次看到它时可能会让人感到困惑。
如果要从catch块中抛出异常,则必须通知方法??/类/ etc.它需要抛出异常。像这样:
1 2 3 4 5 6 7 | public void doStuff() throws MyException { try { //Stuff } catch(StuffException e) { throw new MyException(); } } |
现在你的编译器不会对你大吼大叫:)
不 - 正如Chris Jester-Young所说,它将被抛到层次结构中的下一个try-catch。
不,因为捕获都引用了相同的try块,所以从catch块中抛出将被一个封闭的try块捕获(可能在调用此块的方法中)
它不会被第二个捕获块捕获。每个异常仅在try块内捕获。你可以嵌套尝试(通常不是一个好主意):
1 2 3 4 5 6 7 8 9 10 11 | try { doSomething(); } catch (IOException) { try { doSomething(); } catch (IOException e) { throw new ApplicationException("Failed twice at doSomething" + e.toString()); } } catch (Exception e) { } |
如上所述......
我想补充一点,如果你无法看到发生了什么,如果你不能在调试器中重现问题,你可以在重新抛出新异常之前添加一个跟踪(好的旧System.out.println更糟糕) ,具有像log4j这样的良好日志系统,否则)。
旧帖但"e"变量必须是唯一的:
1 2 3 4 5 6 7 | try { // Do something } catch(IOException ioE) { throw new ApplicationException("Problem connecting to server"); } catch(Exception e) { // Will the ApplicationException be caught here? } |