在catch区块内抛出异常 - 它会被再次捕获吗?

时间:2008-09-27 13:10:52

标签: java exception

这可能看起来像编程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工作。

9 个答案:

答案 0 :(得分:192)

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

答案 1 :(得分:62)

没有。这很容易检查。

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块也会一直运行(除了愚蠢的情况,例如无限循环,通过工具接口连接并杀死线程,重写字节码等)。

答案 2 :(得分:26)

Java语言规范在第14.19.1节中说:

  

如果由于抛出值V而导致try块的执行突然完成,那么可以选择:

     
      
  • 如果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块抛出的任何异常都会丢失。这可能会让你第一次看到它时感到困惑。

答案 3 :(得分:6)

如果要从catch块中抛出异常,则必须通知方法​​/类/ etc.它需要抛出异常。像这样:

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

现在你的编译器不会对你大喊:)

答案 4 :(得分:4)

不 - 正如Chris Jester-Young所说,它将被提升到层次结构中的下一个try-catch。

答案 5 :(得分:1)

如上所述......
我想补充一点,如果你无法看到发生了什么,如果你不能在调试器中重现问题,你可以在重新抛出新异常之前添加一个跟踪(好的旧System.out.println更糟糕) ,有一个很好的日志系统,如log4j否则)。

答案 6 :(得分:1)

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

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

答案 7 :(得分:1)

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

答案 8 :(得分:-3)

旧帖子但“e”变量必须是唯一的:

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