캐치 블록 내부에 던져진 예외 - 다시 잡힐까?
이것은 프로그래밍 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?
}
'programing' 카테고리의 다른 글
{ A=a; B=b; }의 경우 "B=b" 이전에 "A=a"가 엄격히 실행되나? (0) | 2022.05.18 |
---|---|
왜 이렇게 빨갛지?IntelliJ는 모든 선언/방법들이 발견/해결될 수 없다고 생각하는 것 같다. (0) | 2022.05.18 |
vue 구성 요소의 데이터를 편집할 때 입력 유형 날짜의 값을 표시하는 방법은? (0) | 2022.05.18 |
C에서 값을 교환하는 가장 빠른 방법은 무엇인가? (0) | 2022.05.18 |
javac이 내부 또는 외부 명령, 작동 가능한 프로그램 또는 배치 파일로 인식되지 않음 (0) | 2022.05.18 |