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


180

이것은 프로그래밍 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에서 일하고 있습니다.


2
아마도 "이상한 행동"을 설명 할 수 있습니까?
— Jeffrey L Whitledge

ApplicationException이 다른 곳에서 발생하지 않고이 블록으로 전파되지 않습니까?
— sblundy

Eclipse IDE에서 이것을 알았습니다. "새 예외 발생"을 try 블록에 넣도록 강요하고 있지만 이유를 모르겠습니다. 나는 그것을하지 않고 과거에 그것을했습니다. try 블록이 왜 필요한지 모르겠습니다. Google의 많은 예제는 try 블록이 필요없는 사람들을 보여줍니다. if 문 안에 던지기 때문입니까?
— djangofan

답변:


214

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


코드가 이와 같다면, {{catch (Exception e) {System.err.println ( "Catch Exception :"+ e.getClass ()); } catch (IOException e) {System.err.println ( "IOException 잡기 :"+ e.getClass ()); } try 블록의 코드는 IO Exception을 생성합니다. 즉각 일반 Exception 블록으로 이동합니까 아니면 IOException catch 블록으로 이동합니까?
— sofs1

4
@ user3705478 이런 종류의 잘못된 상황을 피하기 위해 코드가 컴파일되지 않습니다. 일반적으로 동일한 try 블록에서 수퍼 클래스를 잡은 후 서브 클래스를 잡을 수 없습니다.
— Chris Jester-Young

감사. 컴파일 시간 오류가 발생합니까? 집에 도착하면 테스트 해 보겠습니다.
— sofs1

@ user3705478에 따라 다르지만 블록 RuntimeException에서 a 를 던지면 catch컴파일 오류가 없습니다.
— 랜디 데브

@AndrewDunn 나는 그것이 user3705478의 질문에 관한 것이 아니라 오히려 부모 예외 catch절이 자식 예외 절 앞에 나열 되면 어떻게되는지 생각합니다 catch. 내 이해는 Java가 이것을 허용하지 않으며 컴파일 타임에 잡힌다는 것입니다.
— Chris Jester-Young

71

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

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 블록은 항상 실행됩니다 (무한 루프, 도구 인터페이스를 통한 연결 및 스레드 종료, 바이트 코드 다시 작성 등).


3
finally물론 피하는 가장 확실한 방법 은 전화하는 것 System.exit입니다. :-P
— Chris Jester-Young

3
@Chris Jester-Young for(;;);는 더 짧고, 언어에 포함되어 있으며 부작용의 방식을 많이 소개하지 않으며 나에게 더 분명합니다.
— Tom Hawtin-tackline

1
System.exitCPU에 친숙합니다! : -O 그러나 네, 물론 이것은 주관적인 기준입니다. 또한, 나는 당신이 코드 골퍼가 될 줄 몰랐습니다. ;-)
— Chris Jester-Young

28

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 블록에서 발생한 예외가 손실된다는 것입니다. 처음 볼 때 혼란 스러울 수 있습니다.


Java 7부터는 try-with-resources 를 사용하지 않도록 추가하고 싶었습니다 . 그런 다음 tryAND가 finally둘 다 발생하면 finally억제되지만 from의 예외에 추가됩니다 try. 경우 catch뿐만 아니라 발생하면 'addSuppressed'를 통해 그 자신을 처리하고 추가하지 않는 한, 당신은 행운에있어 try예외를 - 다음 세 가지가 있습니다.
— LAFK는 모니카의 복직 자 모니카

6

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

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

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


4

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


2

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


2

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

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

비슷한 코드를 작성했습니다. 그러나 나는 확신하지 못한다. catch 블록에서 Thread.sleep ()을 호출하고 싶습니다. 그러나 Thread.sleep은 자체적으로 InterruptedException을 발생시킵니다. 당신의 예에서 보여준 것처럼 그것을하는 것이 옳은가?
— riroo

1

아니오, catch는 모두 같은 try 블록을 참조하므로 catch 블록 내에서 던지는 것은 try try 블록에 의해 잡히게됩니다 (아마도 이것을 호출 한 메소드에서).


-4

이전 게시물이지만 "e"변수는 고유해야합니다.

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

5
이것은 의견이 아니라 답변이어야합니다. 실제 질문을 해결하는 방법은 없습니다. OP 질문에 대한 비판 일뿐입니다.
— Derek W
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.