Java 在 catch 和 finally 子句中抛出异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3779285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 04:53:30  来源:igfitidea点击:

Exception thrown in catch and finally clause

javaexception

提问by Jubstuff

On a question for Java at the university, there was this snippet of code:

关于大学的 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();
        }
    }
}

I was asked to give its output. I answered 13Exception in thread main MyExc2, but the correct answer is 132Exception in thread main MyExc1. Why is it that? I just can't understand where does MyExc2go.

我被要求提供它的输出。我回答了13Exception in thread main MyExc2,但正确的答案是132Exception in thread main MyExc1。为什么会这样?我就是不明白MyExc2去哪里了。

采纳答案by Bert F

Based on reading your answer and seeing how you likely came up with it, I believe you think an "exception-in-progress" has "precedence". Keep in mind:

根据阅读您的答案并了解您可能如何想出它,我相信您认为“正在进行的异常”具有“优先级”。记住:

When an new exception is thrown in a catch block or finally blockthat will propagate out of that block, then the current exception will be aborted (and forgotten) as the new exception is propagated outward. The new exception starts unwinding up the stack just like any other exception, aborting out of the current block (the catch or finally block) and subject to any applicable catch or finally blocks along the way.

当在catch 块或 finally 块中抛出新异常并将传播出该块时,当前异常将随着新异常向外传播而被中止(并忘记)。新异常开始像任何其他异常一样展开堆栈,从当前块(catch 或 finally 块)中止并在此过程中受到任何适用的 catch 或 finally 块的影响。

Note that applicable catch or finally blocksincludes:

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

When a new exception is thrown in a catch block, the new exception is still subject to that catch's finally block, if any.

当在 catch 块中抛出新异常时,新异常仍受该 catch 的 finally 块(如果有)的约束。

Now retrace the execution remembering that, whenever you hit throw, you should abort tracing the current exception and start tracing the new exception.

现在回溯执行,记住,无论何时点击throw,都应该中止跟踪当前异常并开始跟踪新异常。

回答by Uwe Keim

I think you just have to walk the finallyblocks:

我认为你只需要走finally块:

  1. Print "1".
  2. finallyin qprint "3".
  3. finallyin mainprint "2".
  1. 打印“1”。
  2. finallyq打印“3”。
  3. finallymain打印“2”。

回答by Alexander Pogrebnyak

Finally clause is executed even when exception is thrown from anywhere in try/catch block.

即使从 try/catch 块中的任何地方抛出异常,也会执行 finally 子句。

Because it's the last to be executed in the mainand it throws an exception, that's the exception that the callers see.

因为它是最后一个在 中执行main并且抛出异常,这就是调用者看到的异常。

Hence the importance of making sure that the finallyclause does not throw anything, because it can swallow exceptions from the tryblock.

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

回答by Buhake Sindi

This is what Wikipediasays about finally clause:

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

More common is a related clause (finally, or ensure) that is executed whether an exception occurred or not, typically to release resources acquired within the body of the exception-handling block.

更常见的是无论是否发生异常都会执行相关子句(finally 或 ensure),通常是为了释放在异常处理块的主体内获取的资源。

Let's dissect your program.

让我们剖析您的程序。

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

So, 1will be output into the screen, then q()is called. In q(), an exception is thrown. The exception is then caught by Exception ybut it does nothing. A finallyclause is then executed (it has to), so, 3will be printed to screen. Because (in method q()there's an exception thrown in the finallyclause, also q()method passes the exception to the parent stack (by the throws Exceptionin the method declaration) new Exception()will be thrown and caught by catch ( Exception i ), MyExc2exception will be thrown (for now add it to the exception stack), but a finallyin the mainblock will be executed first.

所以,1将被输出到屏幕,然后q()被调用。在q(),抛出异常。然后异常被捕获,Exception y但它什么也不做。甲最后然后子句被执行(它有),所以,3将被打印到屏幕。因为(在方法中q()有一个异常在finally子句中抛出,并且q()方法将异常传递到父堆栈(通过throws Exception方法声明中)new Exception()将被抛出并被捕获catch ( Exception i )MyExc2异常将被抛出(现在将其添加到异常堆栈),但最后main块将被首先执行。

So in,

所以在,

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

A finallyclause is called...(remember, we've just caught Exception iand thrown MyExc2) in essence, 2is printed on screen...and after the 2is printed on screen, a MyExc1exception is thrown. MyExc1is handled by the public static void main(...)method.

一个最后条款被称为...(请记住,我们只是抓住了Exception i,扔MyExc2)在本质上,2是印在屏幕上......而之后2被显示在屏幕上,一个MyExc1异常被抛出。MyExc1public static void main(...)方法处理。

Output:

输出:

"132Exception in thread main MyExc1"

“线程主 MyExc1 中的 132Exception”

Lecturer is correct! :-)

老师说得对!:-)

In essence, if you have a finallyin a try/catch clause, a finally will be executed (aftercatching the exception beforethrowing the caught exception out)

本质上,如果你在 try/catch 子句中有一个finally,一个 finally 将被执行(捕获异常之后,然后将捕获的异常抛出出去)

回答by Garis M Suero

A methodcan't throwtwo exceptions at the same time. It will always throw the last thrown exception, which in this case it will be always the one from the finallyblock.

Amethod不能同时出现throw两个异常。它将始终抛出最后一个 throw exception,在这种情况下,它将始终是finally块中的那个。

When the first exception from method q()is thrown, it will catch'ed and then swallowed by the finally block thrown exception.

当方法q()抛出第一个异常时,它会被捕获,然后被 finally 块抛出的异常吞下。

q() ->thrown new Exception->maincatch Exception->thrownew Exception->finallythrow a new exception(and the one from the catchis "lost")

q() ->抛出new Exception-> maincatch Exception-> thrownew Exception->finally抛出一个新的exception(其中一个catch是“丢失”的)

回答by CodingWithSpike

The easiest way to think of this is imagine that there is a variable global to the entire application that is holding the current exception.

想到这一点的最简单方法是想象有一个全局变量对整个应用程序持有当前异常。

Exception currentException = null;

As each exception is thrown, "currentException" is set to that exception. When the application ends, if currentException is != null, then the runtime reports the error.

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

Also, the finally blocks always run before the method exits. You could then requite the code snippet to:

此外,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
        }
    }
}

The order in which the application executes is:

应用程序执行的顺序是:

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

回答by Vouze

I think this solve the problem :

我认为这可以解决问题:

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

回答by Sly

It is well known that the finally block is executed after the the try and catch and is always executed.... But as you saw it's a little bit tricky sometimes check out those code snippet below and you will that the return and throw statements don't always do what they should do in the order that we expect theme to.

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

Cheers.

干杯。

/////////////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!";

}
////////////////////////////////////////////////// 

回答by Roland

Exceptions in the finally block supersede exceptions in the catch block.

finally 块中的异常取代了 catch 块中的异常。

Quoting from the Java Language Specification 14 edition:

引用Java 语言规范 14 版

If the catch block completes abruptly for reason R, then the finally block is executed. Then there is a choice:

  • If the finally block completes normally, then the try statement completes abruptly for reason R.

  • If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).

如果 catch 块由于原因 R 突然完成,则执行 finally 块。然后有一个选择:

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

  • 如果 finally 块因原因 S 突然完成,则 try 语句因原因 S 突然完成(并且原因 R 被丢弃)。

回答by Luiz Fernando

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

Order:

命令:

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/

https://www.compilejava.net/