IT story

catch 및 finally 절에서 예외가 발생했습니다.

hot-time 2020. 6. 14. 09:48
반응형

catch 및 finally 절에서 예외가 발생했습니다.


대학에서 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가 어디로 가는지 이해할 수 없습니다.


귀하의 답변을 읽고 그 결과를 어떻게 얻었는지 알면, "진행 중 예외"가 "우선 순위"라고 생각합니다. 명심하십시오 :

catch 블록 에서 새 예외가 발생 하거나 해당 블록에서 전파되는 finally 블록 이 발생하면 새 예외가 외부로 전파 될 때 현재 예외가 중단 (및 잊혀짐)됩니다. 새로운 예외는 다른 예외와 마찬가지로 스택을 풀기 시작하여 현재 블록 (캐치 또는 최종 블록)에서 중단되고 적용 가능한 캐치 또는 최종적으로 블록을 따라갑니다.

참고 적용 캐치 또는 finally 블록이 포함되어 있습니다 :

catch 블록에서 새 예외가 발생하더라도 새 예외는 해당 catch의 finally 블록이있는 경우 계속 적용됩니다.

이제에 도달 할 때마다 throw현재 예외 추적을 중단하고 새 예외 추적을 시작해야한다는 점을 기억하여 실행을 다시 추적하십시오.


이것은 무엇 위키 백과 finally 절에 대해 말한다 :

예외가 발생했는지 여부에 관계없이 일반적으로 예외 처리 블록의 본문 내에서 획득 한 리소스를 해제하기 위해 실행되는 관련 절 (최종 또는 보장)이 더 일반적입니다.

프로그램을 해부하자.

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

그래서, 1다음, 화면에 출력 될 것 q()이라고합니다. 에서 q()예외가 발생합니다. 그런 다음 예외가 발생 Exception y하지만 아무 것도 수행하지 않습니다. 마지막 항을 다음 (IT가 있음)이 실행되기 때문에, 3화면을 통해 출력된다. (방법 때문에 q()에 던져 예외 거기에 마지막 절은 또한 q()방법은에 의해 부모 스택에 예외 (패스 throws Exception) 메소드 선언을 new Exception()함으로써 던져 잡힐 것 catch ( Exception i ), MyExc2(예외 스택에 추가 지금은 예외가 발생합니다 )이지만 블록 마지막main먼저 실행됩니다.

그래서

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

마지막 절 (기억, 우리가 잡았습니다 ...라고 Exception i던져 MyExc2) 본질적으로, 2화면에 인쇄되어 있습니다 ... 그리고이 후 2화면에 인쇄하는 MyExc1예외가 발생합니다. MyExc1public static void main(...)방법 으로 처리됩니다 .

산출:

"132 스레드 기본 MyExc1에서 예외"

강사가 맞습니다! :-)

본질적으로 당신이있는 경우에, 마지막으로 시도 / 캐치 절에, 최종적으로는 (실행됩니다 예외를 잡기 전에 잡힌 예외를 던지는)


JLS 11 인용 : 14.20.2. try-finally 및 try-catch-finally의 실행

이유 R로 인해 catch 블록이 갑자기 완료되면 finally 블록이 실행됩니다. 그런 다음 선택이 있습니다.

  • finally 블록이 정상적으로 완료되면 이유 R로 인해 try 문이 갑자기 완료됩니다.

  • 이유 S에 대해 finally 블록이 갑자기 완료되면 이유 S에 대해 try 문이 갑자기 완료됩니다 (및 이유 R은 폐기 됨).


finally 절은 try / catch 블록의 어느 곳에서나 예외가 발생하더라도 실행됩니다.

에서 마지막으로 실행되고 main예외가 발생하기 때문에 호출자가 보는 예외입니다.

따라서이 finally절이 try블록 에서 예외를 삼킬 수 있기 때문에 절이 아무것도 던지지 않도록하는 것이 중요 합니다 .


A methodthrow동시에 두 가지 예외가 될 수 없습니다 . 항상 마지막에 던진 것을 던질 것 exception입니다.이 경우에는 항상 finally블록 에서 나온 것 입니다.

메소드의 첫 번째 예외 q()가 발생하면 catch 된 후 finally 블록에서 예외를 삼킨다.

Q () -> 던져 new Exception -> main catch Exception -> throw new Exception ->이 finally 새로운 던져 exception(과에서 하나의 catch"손실"됩니다)


이것을 생각하는 가장 쉬운 방법은 현재 예외를 보유하고있는 전체 응용 프로그램에 전역 변수가 있다고 상상하는 것입니다.

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
}

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

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

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/


인쇄가 완료 될 때까지 논리가 명확합니다 13. 그런 다음에 던져 예외 q()로 잡힌 catch (Exception i)에서 main()a는 new MyEx2()던져 질 준비가되어 있습니다. 그러나 예외를 발생시키기 전에 먼저 finally블록을 실행해야합니다. 그런 다음 출력이 132되고 finally또 다른 예외가 발생하도록 요청합니다 new MyEx1().

As a method cannot throw more than one Exception, it will always throw the latest Exception. In other words, if both catch and finally blocks try to throw Exception, then the Exception in catch is swallowed and only the exception in finally will be thrown.

Thus, in this program, Exception MyEx2 is swallowed and MyEx1 is thrown. This Exception is thrown out of main() and no longer caught, thus JVM stops and the final output is 132Exception in thread main MyExc1.

In essence, if you have a finally in a try/catch clause, a finally will be executed AFTER catching the exception, but BEFORE throwing any caught exception, and ONLY the lastest exception would be thrown in the end.


I think you just have to walk the finally blocks:

  1. Print "1".
  2. finally in q print "3".
  3. finally in main print "2".

To handle this kind of situation i.e. handling the exception raised by finally block. You can surround the finally block by try block: Look at the below example in 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"

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

참고URL : https://stackoverflow.com/questions/3779285/exception-thrown-in-catch-and-finally-clause

반응형