在catch块中引发异常-会再次被捕获吗?

时间:2020-03-06 14:49:26  来源:igfitidea点击:

这似乎是一个编程101的问题,我以为我知道答案,但是现在发现自己需要仔细检查。在下面的这段代码中,在第一个catch块中引发的异常是否会被下面的常规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块中。

否-正如克里斯·杰斯特·杨(Chris Jester-Young)所说,它将被扔到层次结构中的下一个try-catch。

如上所述
我要补充的是,如果我们看不到正在发生的事情,如果我们无法在调试器中重现该问题,则可以在重新引发新异常之前添加一条跟踪记录(更糟糕的是旧的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) {
}

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

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

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

一个相关且令人困惑的事情是,在try- [catch] -finally结构中,finally块可能会引发异常,如果这样,则try或者catch块引发的任何异常都会丢失。第一次看到它时,可能会造成混乱。