简体   繁体   English

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

[英]Exception thrown inside catch block - will it be caught again?

This may seem like a programming 101 question and I had thought I knew the answer but now find myself needing to double check. 这可能看起来像编程101问题,我原以为我知道答案,但现在发现自己需要仔细检查。 In this piece of code below, will the exception thrown in the first catch block then be caught by the general Exception catch block below? 在下面的这段代码中,第一个catch块中抛出的异常是否会被下面的常规异常捕获块捕获?

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

I always thought the answer would be no, but now I have some odd behaviour that could be caused by this. 我一直认为答案是否定的,但现在我有一些可能由此造成的奇怪行为。 The answer is probably the same for most languages but I'm working in Java. 答案可能与大多数语言相同,但我在Java工作。

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

No. It's very easy to check. 不,这很容易检查。

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");
        }
    }
}

Should print: 应打印:

In catch IOException: class java.io.IOException
In finally
Exception in thread "main" java.lang.RuntimeException
        at Catch.main(Catch.java:8)

Technically that could have been a compiler bug, implementation dependent, unspecified behaviour, or something. 从技术上讲,这可能是编译器错误,依赖于实现,未指定的行为或其他东西。 However, the JLS is pretty well nailed down and the compilers are good enough for this sort of simple thing (generics corner case may be a different matter). 然而,JLS已经很好地确定了,并且编译器对于这种简单的事情已经足够好了(泛型角落情况可能是另一回事)。

Also note, if you swap around the two catch blocks, it wont compile. 还要注意,如果你交换两个catch块,它就不会编译。 The second catch would be completely unreachable. 第二次捕获将完全无法到达。

Note the finally block always runs even if a catch block is executed (other than silly cases, such as infinite loops, attaching through the tools interface and killing the thread, rewriting bytecode, etc.). 注意,即使执行了一个catch块,finally块也会一直运行(除了愚蠢的情况,例如无限循环,通过工具接口附加并杀死线程,重写字节码等)。

The Java Language Specification says in section 14.19.1: 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: 如果try块的执行由于抛出值V而突然完成,那么有一个选择:

  • 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. 如果V的运行时类型可分配给try语句的任何catch子句的Parameter,则选择第一个(最左边)这样的catch子句。 The value V is assigned to the parameter of the selected catch clause, and the Block of that catch clause is executed. 值V分配给所选catch子句的参数,并执行该catch子句的Block。 If that block completes normally, then the try statement completes normally; 如果该块正常完成,则try语句正常完成; if that block completes abruptly for any reason, then the try statement completes abruptly for the same reason. 如果该块由于任何原因突然完成,则try语句突然完成,原因相同。

Reference: http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134 参考: http//java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134

In other words, the first enclosing catch that can handle the exception does, and if an exception is thrown out of that catch, that's not in the scope of any other catch for the original try, so they will not try to handle it. 换句话说,可以处理异常的第一个封闭catch,如果从该catch中抛出异常,那么它不在原始try的任何其他catch的范围内,因此它们不会尝试处理它。

One related and confusing thing to know is that in a try-[catch]-finally structure, a finally block may throw an exception and if so, any exception thrown by the try or catch block is lost. 一个相关且令人困惑的事情是,在try- [catch] -finally结构中,finally块可能抛出异常,如果是这样,try或catch块抛出的任何异常都会丢失。 That can be confusing the first time you see it. 第一次看到它时可能会让人感到困惑。

If you want to throw an exception from the catch block you must inform your method/class/etc. 如果要从catch块中抛出异常,则必须通知方法​​/类/ etc. that it needs to throw said exception. 它需要抛出异常。 Like so: 像这样:

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

And now your compiler will not yell at you :) 现在你的编译器不会对你大吼大叫:)

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

As said above... 如上所述......
I would add that if you have trouble seeing what is going on, if you can't reproduce the issue in the debugger, you can add a trace before re-throwing the new exception (with the good old System.out.println at worse, with a good log system like log4j otherwise). 我想补充一点,如果你无法看到发生了什么,如果你不能在调试器中重现问题,你可以在重新抛出新异常之前添加一个跟踪(好的旧System.out.println更糟糕) ,具有像log4j这样的良好日志系统,否则)。

It won't be caught by the second catch block. 它不会被第二个捕获块捕获。 Each Exception is caught only when inside a try block. 每个异常仅在try块内捕获。 You can nest tries though (not that it's a good idea generally): 你可以嵌套尝试(通常不是一个好主意):

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

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

Old post but "e" variable must be unique: 旧帖但“e”变量必须是唯一的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM