这可能看起来像编程101问题,我原以为我知道答案,但现在发现自己需要仔细检查.在下面这段代码中,第一个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"); } } }
应打印:
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节中说:
如果try块的执行由于抛出值V而突然完成,那么有一个选择:
如果V的运行时类型可分配给try语句的任何catch子句的Parameter,则选择第一个(最左边)这样的catch子句.值V分配给所选catch子句的参数,并执行该catch子句的Block.如果该块正常完成,则try语句正常完成; 如果该块由于任何原因突然完成,则try语句突然完成,原因相同.
参考: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. 它需要抛出异常.像这样:
public void doStuff() throws MyException { try { //Stuff } catch(StuffException e) { throw new MyException(); } }
现在你的编译器不会对你大吼大叫:)