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 Exception
) new Exception()
将被抛出并被catch ( Exception i )
, MyExc2
exception将被抛出(现在将其添加到exception堆栈),但最后在main
块中将首先执行。
所以在,
catch ( Exception i ) { throw( new MyExc2() ); } finally { System.out.print(2); throw( new MyExc1() ); }
最后一个子句被调用…(记住,我们刚刚捕获了Exception i
和抛出的MyExc2
), 2
被打印在屏幕上…并且在屏幕上打印2
之后,引发了MyExc1
exception。 MyExc1
由public 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”。
-
finally
在q
打印“3”。 -
finally
在main
“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); } } }