catch和finally子句中抛出的exception

在大学的Java问题上,有这样的代码片段:

class MyExc1 extends Exception {} class MyExc2 extends Exception {} class MyExc3 extends MyExc2 {} public class C1 { public static void main(String[] args) throws Exception { try { System.out.print(1); q(); } catch (Exception i) { throw new MyExc2(); } finally { System.out.print(2); throw new MyExc1(); } } static void q() throws Exception { try { throw new MyExc1(); } catch (Exception y) { } finally { System.out.print(3); throw new Exception(); } } } 

我被要求给出它的输出。 我13Exception in thread main MyExc2回答了13Exception in thread main MyExc2 ,但正确答案是132Exception in thread main MyExc1 。 为什么呢? 我无法理解MyExc2在哪里。

基于阅读你的答案,并看到你如何提出这个答案,我相信你认为一个“进行中的例外”有“优先”。 记住:

当一个新的exception在一个catch块或最后一个块中被抛出时,那么当新的exception向外传播时,当前的exception将被中止(并被遗忘)。 新exception开始展开堆栈,就像任何其他exception一样,从当前块(catch或finally块)中取消,并沿用任何适用的catch或finally块。

请注意, 适用的catch或finally块包括:

当在catch块中抛出一个新的exception时,新的exception仍然受到该catch的finally块的影响(如果有的话)。

现在回顾一下执行过程,记住,每当你点击throw ,你应该中止跟踪当前的exception,并开始追踪新的exception。

这就是维基百科关于finally子句所说的:

更常见的是一个相关的子句(最后,或确保)执行是否发生exception,通常是释放在exception处理块体内获取的资源。

我们来剖析你的程序。

 try { System.out.print(1); q(); } 

所以, 1将被输出到屏幕上,然后q()被调用。 在q() ,抛出exception。 exception然后由Exception y捕获,但它什么都不做。 然后执行finally子句(它必须),所以3将被打印到屏幕上。 因为(在方法q()finally子句抛出的exception,所以q()方法将exception传递给父堆栈(通过在方法声明中throws Exceptionnew Exception()将被抛出并被catch ( Exception i )MyExc2exception将被抛出(现在将其添加到exception堆栈),但最后main块中将首先执行。

所以在,

 catch ( Exception i ) { throw( new MyExc2() ); } finally { System.out.print(2); throw( new MyExc1() ); } 

最后一个子句被调用…(记住,我们刚刚捕获了Exception i和抛出的MyExc2 ), 2被打印在屏幕上…并且在屏幕上打印2之后,引发了MyExc1exception。 MyExc1public static void main(...)方法处理。

输出:

“主线程MyExc1中的132Exception”

讲师是对的! 🙂

实质上 ,如果你在try / catch子句中有一个finally ,那么finally将被执行( 捕获exception之前捕获exception)

引用JLS 9:14.20.2。 try-finally和try-catch-finally的执行

如果由于原因R catch块突然完成,则执行finally块。 那么有一个select:

  • 如果finally块正常完成,那么由于原因R,try语句突然完成。

  • 如果finally块由于S原因而突然完成,那么try语句因为原因S突然完成(并且原因R被丢弃)。

即使从try / catch块中的任何位置抛出exception,finally子句也会被执行。

因为这是main执行的最后一个,它引发一个exception,这是调用者看到的exception。

因此确保finally子句不会抛出任何东西的重要性,因为它可以吞噬try块中的exception。

一个method不能同时throw两个exception。 它总是会抛出最后抛出的exception ,在这种情况下,它将始终是finally块中的exception

当方法q()的第一个exception被抛出时,它会被finally块抛出的exception抓住然后吞下。

q() – >抛出new Exception – > main catch Exception – > throw new Exception – > finally抛出一个新的exception (和catch的一个是“失去”)

想想这个最简单的方法是想象一下,在整个应用程序中有一个可变的全局variables来持有当前exception。

 Exception currentException = null; 

当每个exception被抛出时,“currentException”被设置为该exception。 当应用程序结束时,如果currentException是!= null,则运行时报告错误。

另外,finally方法总是在方法退出之前运行。 然后,您可以将代码片段复原到:

 public class C1 { public static void main(String [] argv) throws Exception { try { System.out.print(1); q(); } catch ( Exception i ) { // <-- currentException = Exception, as thrown by q()'s finally block throw( new MyExc2() ); // <-- currentException = MyExc2 } finally { // <-- currentException = MyExc2, thrown from main()'s catch block System.out.print(2); throw( new MyExc1() ); // <-- currentException = MyExc1 } } // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console. static void q() throws Exception { try { throw( new MyExc1() ); // <-- currentException = MyExc1 } catch( Exception y ) { // <-- currentException = null, because the exception is caught and not rethrown } finally { System.out.print(3); throw( new Exception() ); // <-- currentException = Exception } } } 

应用程序执行的顺序是:

 main() { try q() { try catch finally } catch finally } 

我想你只需要走finally街区:

  1. 打印“1”。
  2. finallyq打印“3”。
  3. finallymain “2”。

这里只是一个猜测,但是“finally”块总是被执行。 所以,我的猜测是,因为有一个exception抛出,在finally块,这是一个优先。

众所周知的是,finally块在try和catch之后执行,并且总是被执行。但是正如你所看到的那样有点棘手,有时候请查看下面的代码片段,你会发现返回和throw语句不会不要总是按照我们所期望的主题来做他们应该做的事情。

干杯。

 /////////////Return dont always return/////// try{ return "In Try"; } finally{ return "In Finally"; } //////////////////////////////////////////// //////////////////////////////////////////// while(true) { try { return "In try"; } finally{ break; } } return "Out of try"; /////////////////////////////////////////// /////////////////////////////////////////////////// while (true) { try { return "In try"; } finally { continue; } } ////////////////////////////////////////////////// /////////////////Throw dont always throw///////// try { throw new RuntimeException(); } finally { return "Ouuuups no throw!"; } ////////////////////////////////////////////////// 

我认为这解决了这个问题:

 boolean allOk = false; try{ q(); allOk = true; } finally { try { is.close(); } catch (Exception e) { if(allOk) { throw new SomeException(e); } } }