catch和finally子句抛出异常

时间:2010-09-23 14:15:09

标签: java exception exception-handling

关于大学的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的去向。

12 个答案:

答案 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个异常。 MyExc1public 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抛出一个新exceptioncatch中的一个“丢失” )

答案 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块:

  1. 打印“1”。
  2. finallyq打印“3”。
  3. finallymain打印“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)

https://www.compilejava.net/

答案 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。换句话说,如果catchfinally块都试图抛出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);
     }
  }
}