catch 및 finally 절에서 예외 발생


158

대학에서 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.

답변:


171

귀하의 답변을 읽고 어떻게 생각해 냈는지 살펴보면 "예외 진행 중"에 "우선 순위"가 있다고 생각합니다. 다음 사항에 유의하십시오.

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

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

catch 블록에서 새 예외가 throw 될 때 새 예외는 여전히 해당 catch의 finally 블록 (있는 경우)의 적용을받습니다.

이제를 누를 때마다 throw현재 예외 추적을 중단하고 새 예외 추적을 시작해야 함 을 기억하여 실행을 다시 추적하십시오.


7
«당신의 답변을 읽고 그것을 어떻게 생각해
냈는지에 근거

40

이것은 Wikipedia 가 finally 절에 대해 말하는 것입니다.

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

프로그램을 분석해 보겠습니다.

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

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

그래서

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

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

산출:

"스레드 주 MyExc1의 132Exception"

강사가 맞습니다! :-)

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


catch이후 실행되는 q()줬어요 Exception자체에서 finally차단합니다.
Péter Török

"q ()에서는 예외가 발생하지만 예외가 완전히 발생하기 전에 finally 절이 먼저 실행되므로 3이 화면에 인쇄됩니다."Er ... 아니요, 발생하는 첫 번째 예외 q는 실행을 (이 예외를 삼키는) 빈 catch블록 을 . 마지막으로 인쇄를 차단하는 것을 특징으로 하고 덕분에 새로운 예외 발생 의가 부모를 스택을 전달합니다. qfinallyq3qthrows Exception
Powerlord

39

finally 블록의 예외는 catch 블록의 예외를 대체합니다.

Java Language Specification 14 에디션 에서 인용 :

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

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

  • finally 블록이 이유 S로 인해 갑자기 완료되면 try 문이 이유 S로 인해 갑자기 완료되고 이유 R은 삭제됩니다.


21

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

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

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


5
try / catch 블록에서 예외가 발생하지 않은 경우에도 실행됩니다.
nanda

2
+1 : OP가 이미 이해하는 것처럼 보이는 전체 스택을 구불 구불 한 상태로 직접 지시합니다.
Powerlord

9

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

메서드의 첫 번째 예외 q()가 throw되면 finally 블록에서 throw 된 예외가 포착 된 다음 삼켜집니다.

q () -> 던진 new Exception -> main catch Exception -> throw new Exception -> finally 새 던지기 exception(그리고 그 중 하나 catch는 "잃어버린"것임)


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
}

2
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/


1
이 코드 스 니펫이 해결책이 될 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 도움이됩니다. 당신이 미래의 독자에 대한 질문에 대답하는 것을 기억하고, 그 사람들은 당신의 코드 제안 이유를 알고하지 않을 수 있습니다
라훌 굽타에게

1

finally 블록은 try and 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!";

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

1

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

메서드는 둘 이상을 throw 할 수 없으므로 Exception항상 최신 항목을 throw합니다 Exception. 즉, catchfinally블록 이 모두 를 throw하려고 Exception하면 Exceptionin catch가 삼켜 지고 in 예외 만 finallythrow됩니다.

따라서이 프로그램에서 Exception MyEx2은 삼켜지고 MyEx1throw됩니다. 이 예외는 밖으로 던져지고 main()더 이상 포착되지 않으므로 JVM이 중지되고 최종 출력은 다음과 같습니다.132Exception in thread main MyExc1 입니다.

당신이이 경우 본질적으로, finallyA의 try/catch절, a는 finally실행됩니다 예외를 잡기 후에 , 그러나 어떤 잡은 예외를 던지기 전에 , 만 최신 예외는 결국 던져 질 것이다 .


0

나는 당신이 finally블록 을 걸어야한다고 생각합니다 .

  1. "1"을 인쇄하십시오.
  2. finally에서 q"3"인쇄 할 수 있습니다.
  3. finally에서 main"2"를 인쇄 할 수 있습니다.

0

이런 종류의 상황을 처리하기 위해, 즉 finally 블록에서 발생한 예외를 처리합니다. finally 블록을 try 블록으로 둘러 쌀 수 있습니다. 아래 예제를 파이썬으로보십시오.

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"

-1

나는 이것이 문제를 해결한다고 생각한다.

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

3
어떤 문제를 "해결"하시겠습니까? 시험에 나오는 질문을 의미합니까? 이미 대답했습니다. 주어진 코드의 문제를 의미한다면 시험 문제이기 때문에 그것을 비난 할 의미가 없습니다.
Earth Engine
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.