关于大学的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
,但正确的答案是132Exception in thread main MyExc1
。为什么会这样?我无法理解MyExc2的去向。
答案 0 :(得分:145)
在阅读你的答案并了解你如何提出答案的基础上,我相信你认为“正在进行中的异常”具有“优先权”。请记住:
当一个新的异常抛出一个 catch块或finally块会传播出该块时,当前的异常将被中止(并被遗忘),因为新的异常是向外传播。新异常开始展开堆栈,就像任何其他异常一样,从当前块(catch或finally块)中止,并受到任何适用的catch或最终阻塞。
请注意适用的catch或finally块包括:
当在catch块中抛出新异常时,新异常仍然受该catch的finally块(如果有)的影响。
现在回溯执行,记住每次点击throw
时,都应该中止跟踪当前异常并开始跟踪新异常。
答案 1 :(得分:37)
这是Wikipedia关于finally子句的说法:
更常见的是相关条款 (最后,或确保)执行 是否发生异常, 通常是释放资源 在体内获得 异常处理块。
让我们剖析您的计划。
try {
System.out.print(1);
q();
}
因此,1
将输出到屏幕,然后调用q()
。在q()
中,抛出异常。然后由Exception y
捕获该异常,但它什么也没做。然后执行 finally 子句(必须),因此,3
将被打印到屏幕上。因为(在方法q()
中, finally 子句中抛出了异常,所以q()
方法也将异常传递给父堆栈(由方法中的throws Exception
传递声明)new Exception()
将被catch ( Exception i )
抛出并捕获,MyExc2
异常将被抛出(现在将其添加到异常堆栈中),但最终 in main
块将首先执行。
所以,
catch ( Exception i ) {
throw( new MyExc2() );
}
finally {
System.out.print(2);
throw( new MyExc1() );
}
一个 finally 子句被调用...(记住,我们刚刚捕获Exception i
并抛出MyExc2
)本质上,2
被打印在屏幕...并且在屏幕上打印2
后,会抛出MyExc1
个异常。 MyExc1
由public static void main(...)
方法处理。
输出:
“线程主MyExc1中的132Exception”
讲师是对的! : - )
本质上,如果你在try / catch子句中有 finally ,那么将执行finally( >捕获异常< strong>之前抛出捕获的异常
答案 2 :(得分:31)
从JLS 11: 14.20.2. Execution of try-finally and try-catch-finally
引用如果catch块因为R而突然完成,那么最后 块被执行。然后有一个选择:
如果finally块正常完成,则try语句突然完成,原因为R。
如果finally块因为S而突然完成,那么try语句突然完成原因S(并且原因R被丢弃)。
答案 3 :(得分:21)
即使从try / catch块中的任何地方抛出异常,也会执行finally子句。
因为它是最后一个在main
中执行并且它抛出异常,这是调用者看到的异常。
因此确保finally
子句不会抛出任何内容的重要性,因为它可以吞噬try
块中的异常。
答案 4 :(得分:8)
method
不能同时throw
两个例外。它将始终抛出最后抛出的exception
,在这种情况下,它将始终是finally
块中的那个。
当抛出方法q()
的第一个异常时,它会被最后一个块抛出异常捕获然后吞噬。
q() - &gt; 抛出new Exception
- &gt; main
catch Exception
- &gt; throw
new Exception
- &gt; finally
抛出一个新exception
(catch
中的一个“丢失” )
答案 5 :(得分:3)
考虑到这一点的最简单方法是假设整个应用程序存在一个变量全局,它保持当前异常。
Exception currentException = null;
抛出每个异常时,“currentException”设置为该异常。当应用程序结束时,如果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
}
答案 6 :(得分:1)
众所周知,finally块在try和catch之后执行并且始终执行.... 但是正如你所看到的那样有点棘手,有时会查看下面的代码片段,你会那样做 return和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!";
}
//////////////////////////////////////////////////
答案 7 :(得分:0)
我认为你只需要走finally
块:
finally
在q
打印“3”。finally
在main
打印“2”。答案 8 :(得分:0)
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("TryA L1\n");
q();
System.out.print("TryB L1\n");
}
catch (Exception i) {
System.out.print("Catch L1\n");
}
finally {
System.out.print("Finally L1\n");
throw new MyExc1();
}
}
static void q() throws Exception {
try {
System.out.print("TryA L2\n");
q2();
System.out.print("TryB L2\n");
}
catch (Exception y) {
System.out.print("Catch L2\n");
throw new MyExc2();
}
finally {
System.out.print("Finally L2\n");
throw new Exception();
}
}
static void q2() throws Exception {
throw new MyExc1();
}
}
订单:
TryA L1
TryA L2
Catch L2
Finally L2
Catch L1
Finally L1
Exception in thread "main" MyExc1 at C1.main(C1.java:30)
答案 9 :(得分:0)
要处理这种情况,即处理由finally块引发的异常。您可以按try块包围finally块:在python中查看以下示例:
try:
fh = open("testfile", "w")
try:
fh.write("This is my test file for exception handling!!")
finally:
print "Going to close the file"
fh.close()
except IOError:
print "Error: can\'t find file or read data"
答案 10 :(得分:0)
逻辑清楚,直到完成打印13
。然后,q()
中引发的异常被catch (Exception i)
中的main()
捕获,并且准备抛出new MyEx2()
。但是,在引发异常之前,必须首先执行finally
块。然后输出变为132
,并且finally
要求抛出另一个异常new MyEx1()
。
由于方法不能抛出多个Exception
,因此它将始终抛出最新的Exception
。换句话说,如果catch
和finally
块都试图抛出Exception
,则捕获的Exception
被 吞噬 ,仅会抛出finally
中的异常。
因此,在此程序中,吞下了异常MyEx2
,并抛出了MyEx1
。该异常从main()
中抛出,不再被捕获,因此JVM停止并且最终输出为132Exception in thread main MyExc1
。
从本质上讲,如果您在finally
子句中有try/catch
,则{strong>捕获到异常后将执行finally
,但是会抛出任何捕获的异常,并且最后只会抛出最新的异常。
答案 11 :(得分:-1)
我认为这解决了这个问题:
boolean allOk = false;
try{
q();
allOk = true;
} finally {
try {
is.close();
} catch (Exception e) {
if(allOk) {
throw new SomeException(e);
}
}
}