programing

캐치 블록 내부에 던져진 예외 - 다시 잡힐까?

prostudy 2022. 5. 18. 21:56
반응형

캐치 블록 내부에 던져진 예외 - 다시 잡힐까?

이것은 프로그래밍 101 문제처럼 보일 수 있고, 나는 답을 알고 있다고 생각했지만, 이제는 다시 한번 확인해야 할 필요가 있는 나 자신을 발견했다.아래 코드 조각에서 첫 번째 캐치 블록에 던져진 예외가 아래의 일반 예외 캐치 블록에 의해 잡힐 것인가?

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

나는 항상 아니라고 생각했지만, 지금 나는 이것에 의해 야기될 수 있는 이상한 행동을 하고 있다.대부분의 언어들은 아마 같겠지만 나는 자바에서 일하고 있어.

아니, 새것부터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");
        }
    }
}

인쇄 여부:

캐치 IOException: class java.io.IOException드디어스레드 "main" java.lang의 예외.RuntimeExceptionCatch.main(Catch.java:8)에서

엄밀히 말하면 컴파일러 버그, 구현에 의존하는, 지정되지 않은 행동 또는 그 어떤 것이었을 수 있다.그러나 JLS는 상당히 잘 못박혀 있고 컴파일러는 이런 종류의 간단한 것에 충분하다(세대 코너 케이스는 다른 문제일 수 있다).

또한 두 개의 캐치 블록을 교환하면 컴파일되지 않는다.두 번째 어획물은 전혀 접근할 수 없을 것이다.

캐치 블록이 실행되더라도(무한 루프, 툴 인터페이스를 통해 연결, 스레드 제거, 바이트 코드 다시 쓰기 등) 최종 블록은 항상 실행된다는 점에 유의하십시오.

자바 언어 규격에는 제14.19.1절에 다음과 같이 명시되어 있다.

값 V의 투척으로 인해 시도 블록의 실행이 갑자기 완료되는 경우 다음과 같은 옵션이 있다.

  • V의 런타임 유형이 시도문의 캐치 절에 대한 매개 변수에 할당할 수 있는 경우, 첫 번째(맨 왼쪽) 해당 캐치 절을 선택한다.V 값은 선택한 캐치 절의 파라미터에 할당되며, 해당 캐치 절의 Block이 실행된다.해당 블록이 정상적으로 완료되면 시도문은 정상적으로 완료되며, 어떤 이유로든 해당 블록이 갑자기 완료되는 경우 시도문은 같은 이유로 갑자기 완료된다.

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

즉, 예외를 처리할 수 있는 첫 번째 둘러싸인 캐치가 그러하며, 만약 예외를 그 캐치에서 내팽개친다면, 그것은 원래 시도를 위한 다른 캐치 범위에 속하지 않기 때문에, 그들은 그것을 처리하려고 하지 않을 것이다.

한 가지 관련되고 혼란스러운 것은 최종적인 시도 구조에서 최종 블록은 예외를 발생시킬 수 있으며, 그렇다면 시도 또는 캐치 블록에 의해 던져지는 예외는 손실된다는 점이다.처음 봤을 때 헷갈릴 수 있어.

캐치 블록에서 예외를 적용하려면 메서드/클래스/etc에 해당 예외를 적용해야 함을 알려야 한다.이와 같이:

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

그리고 이제 당신의 컴파일러는 당신에게 소리를 지르지 않을 것이다 :)

아니 -- Chris Jester-Young이 말했듯이, 그것은 계층 구조에서 다음 시합을 위해 던져질 것이다.

위에서 말한 바와 같이...
나는 당신이 무슨 일이 일어나고 있는지 보는 데 문제가 있다면, 디버거에서 문제를 재현할 수 없다면, 새로운 예외를 다시 던지기 전에 추적을 추가할 수 있다고 덧붙인다(더 나쁜 경우에는 log4j와 같은 좋은 로그 시스템을 가지고 있다.

두 번째 캐치블록에는 잡히지 않을 것이다.각 예외는 시도 블록 내에서만 발견된다.그래도 시도해볼 수는 있다(일반적으로 좋은 아이디어는 아니다).

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

아니, 캐치 블록은 모두 동일한 시도 블록을 의미하기 때문에 캐치 블록 내에서 던지면 동봉된 시도 블록(아마도 이것을 부르는 방식으로)에 의해 잡힐 것이다.

이전 포스트지만 "e" 변수는 고유해야 함:

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

참조URL: https://stackoverflow.com/questions/143622/exception-thrown-inside-catch-block-will-it-be-caught-again

반응형