[java] 캐치 블록 내부에 예외가 발생했습니다. 다시 포착됩니까?

이것은 프로그래밍 101 질문처럼 보일 수 있으며 대답을 알고 있지만 다시 확인해야한다고 생각했습니다. 아래의이 코드에서, 첫 번째 catch 블록에서 발생한 예외가 아래의 일반 Exception catch 블록에 의해 포착됩니까?

try {
  // Do something
} catch(IOException e) {
  throw new ApplicationException("Problem connecting to server");
} catch(Exception e) {
  // Will the ApplicationException be caught here?
}

나는 항상 대답이 ‘아니오’라고 생각했지만 지금은 이것으로 인해 이상한 행동을 할 수 있습니다. 대답은 아마도 대부분의 언어에서 동일하지만 Java에서 일하고 있습니다.



답변

새로운 throw것은 try직접 블록에 없기 때문에 아닙니다 .


답변

아니요. 확인하기가 매우 쉽습니다.

public class Catch {
    public static void main(String[] args) {
        try {
            throw new java.io.IOException();
        } catch (java.io.IOException exc) {
            System.err.println("In catch IOException: "+exc.getClass());
            throw new RuntimeException();
        } catch (Exception exc) {
            System.err.println("In catch Exception: "+exc.getClass());
        } finally {
            System.err.println("In finally");
        }
    }
}

인쇄해야합니다 :

catch IOException에서 : 클래스 java.io.IOException
마침내
스레드 "main"의 예외 java.lang.RuntimeException
        Catch.main (Catch.java:8)에서

기술적으로는 컴파일러 버그, 구현 의존적, 지정되지 않은 동작 등일 수 있습니다. 그러나 JLS는 잘 정리되어 있으며 컴파일러는 이런 종류의 간단한 일에 충분합니다 (일반 코너 케이스는 다를 수 있습니다).

또한 두 catch 블록을 서로 바꾸면 컴파일되지 않습니다. 두 번째 캐치는 완전히 도달 할 수 없습니다.

catch 블록이 실행 되더라도 finally 블록은 항상 실행됩니다 (무한 루프, 도구 인터페이스를 통한 연결 및 스레드 종료, 바이트 코드 다시 작성 등).


답변

Java 언어 사양은 섹션 14.19.1에 나와 있습니다.

값 V가 발생하여 try 블록의 실행이 갑자기 완료되면 다음을 선택할 수 있습니다.

  • V의 런타임 유형이 try 문의 모든 catch 절의 매개 변수에 지정 가능한 경우, 첫 번째 (가장 왼쪽) catch 절이 선택됩니다. 선택한 catch 절의 매개 변수에 V 값이 할당되고 해당 catch 절의 블록이 실행됩니다. 해당 블록이 정상적으로 완료되면 try 문이 정상적으로 완료됩니다. 어떤 이유로 든 해당 블록이 갑자기 완료되면 try 문도 같은 이유로 갑자기 완료됩니다.

참조 :
http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134

다시 말해, 예외를 처리 할 수있는 첫 번째 엔 클로징 캐치가 예외를 처리하는 경우 원래 시도에 대한 다른 캐치 범위에 속하지 않으므로 처리하려고 시도하지 않습니다.

한 가지 관련되고 혼란스러운 점은 try- [catch] -finally 구조에서 finally 블록에서 예외가 발생할 수 있으며, 그렇다면 try 또는 catch 블록에서 발생한 예외가 손실된다는 것입니다. 처음 볼 때 혼란 스러울 수 있습니다.


답변

catch 블록에서 예외를 발생 시키려면 메소드 / 클래스 등에 게 알려야합니다. 그 예외를 던져야합니다. 이렇게 :

public void doStuff() throws MyException {
    try {
        //Stuff
    } catch(StuffException e) {
        throw new MyException();
    }
}

그리고 지금 컴파일러는 당신에게 소리 지르지 않을 것입니다 🙂


답변

아니요-Chris Jester-Young이 말했듯이 계층 구조의 다음 try-catch까지 발생합니다.


답변

위에서 말했듯이 …
나는 무슨 일이 일어나고 있는지 보는 데 어려움이 있다면 디버거에서 문제를 재현 할 수 없다면 새로운 예외를 다시 던지기 전에 추적을 추가 할 수 있다고 덧붙입니다. .out.println 나쁘게, 그렇지 않으면 log4j와 같은 좋은 로그 시스템).


답변

두 번째 catch 블록에 걸리지 않습니다. 각 예외는 try 블록 내부에서만 발생합니다. 그래도 시도를 중첩 할 수 있습니다 (일반적으로 좋은 생각은 아닙니다) :

try {
    doSomething();
} catch (IOException) {
   try {
       doSomething();
   } catch (IOException e) {
       throw new ApplicationException("Failed twice at doSomething" +
       e.toString());
   }
} catch (Exception e) {
}