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

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

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

我一直认为答案是否定的,但现在我有一些奇怪的行为可能是由这引起的。大多数语言的答案可能都是一样的,但我用的是Java。

262835 次浏览

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

不——正如Chris Jester-Young所说,它将被抛到等级中的下一个尝试接球。

如上所述 我想补充的是,如果你很难看到正在发生的事情,如果你不能在调试器中重现这个问题,你可以在重新抛出新异常之前添加一个跟踪(最坏的情况是使用旧的system .out.println,否则使用像log4j这样的日志系统)

不。这很容易检查。

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

它不会被第二个catch块捕获。每个异常仅在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块捕获(可能在调用此块的方法中)

Java语言规范在14.19.1节中说:

如果try块的执行因为抛出值V而突然结束,那么有一个选择:

  • 如果运行时类型V可赋值给try语句的任何catch子句的Parameter,则选择第一个(最左边)这样的catch子句。将值V赋给所选catch子句的参数,并执行该catch子句的Block。如果该块正常完成,则try语句正常完成;如果该块因为某种原因突然结束,那么try语句也会因为同样的原因突然结束。
< p >参考: http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134 < / p >

换句话说,第一个可以处理异常的封闭捕获可以,如果从该捕获抛出异常,则该异常不在原始try的任何其他捕获的范围内,因此它们不会尝试处理它。

需要知道的一件相关且令人困惑的事情是,在try-[catch]-finally结构中,finally块可能会抛出异常,如果是这样,try或catch块抛出的任何异常都会丢失。第一次看到的时候可能会感到困惑。

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

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

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

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

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