예외를 잡아서 다시 던지지 만 예외는 아닙니다.


10

나는 다음과 같은 코드를 발견했다.

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() {
    throw new RuntimeException();
}

등이 보이기 때문에이 코드는 나를 놀라게 run()-method가 던지는 능력 Exception이 잡는다 이후, Exception다음을 rethrows하지만 방법은 던져 선언되지 Exception분명히 할 필요가 없습니다. 이 코드는 Java 11 이상에서 정상적으로 컴파일됩니다.

내 기대 는 -method throws Exception에서 선언해야한다는 것입니다 run().

추가 정보

비슷한 방식 doSomething으로 던지기 로 선언되면 잡히고 다시 던져도 -method IOException에만 선언하면 됩니다 .IOExceptionrun()Exception

void run() throws IOException {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() throws IOException {
    // ... whatever code you may want ...
}

질문

Java는 일반적으로 명확성을 좋아합니다.이 동작의 이유는 무엇입니까? 항상 이렇게 했습니까? Java 언어 사양에서 run()메소드가 throws Exception위의 코드 스 니펫에서 선언 할 필요가없는 것은 무엇입니까? (내가 추가하면 IntelliJ Exception는 절대 던져지지 않는다고 경고합니다 .)


3
흥미 롭군 어떤 컴파일러를 사용하고 있습니까? IDE 컴파일러 인 경우 다음을 확인하십시오 javac-Eclipse 컴파일러가 더 관대 한 경우를 겪었습니다.
M. Prokhorov

2
openjdk-8에서이 동작을 재현 할 수 있습니다. 특히 -source 1.6플래그를 사용하여 컴파일하면 예상대로 컴파일 오류가 발생합니다. 소스 호환성 7로 컴파일해도 컴파일 오류가 발생 하지 않습니다
Vogel612

1
Java 7부터 컴파일러가 더 똑똑해 보이고 실제 예외에 대해 더 많은 검사를 수행합니다.
michalk

2
이 질문은 중복되지 않으며 답변은 내가 제공 한 링크에서 찾을 수 있습니다In detail, in Java SE 7 and later, when you declare one or more exception types in a catch clause, and rethrow the exception handled by this catch block, the compiler verifies that the type of the rethrown exception meets the following conditions : 1. 1. The try block is able to throw it. 2. There are no other preceding catch blocks that can handle it. 3. It is a subtype or supertype of one of the catch clause's exception parameters.
michalk

2
현재 표시 중복 확실히 관련이 있지만, IMO 상세한 충분한 답을 제공하지 않습니다. 거기 에 대한 답변에 대한 의견 에는 JLS 에 대한 하나의 링크가 있으며 그 정보는 없습니다.
Simon Forsberg

답변:


0

JLS귀하의 질문에 답변 한대로 스캔하지 않았으므로이 답변을 소금 한알과 함께 복용하십시오. 나는 그것을 의견으로 만들고 싶었지만 너무 클 것입니다.


때로는 재미 있습니다. javac어떤 경우에는 (예 : 귀하의 경우와 같이) 꽤 "똑똑한" 방법 이지만 나중에 처리 할 다른 많은 것들을 남겨 둡니다 JIT. 이 경우, 컴파일러는 단지 a만이 RuntimeException잡힐 것이라고 "알 수있다" . 이것은 당신이 던지는 유일한 것입니다 doSomething. 코드를 약간 변경 한 경우 :

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

당신은 다른 행동을 보게 될 것입니다. 이제는 당신이 던진 javac새로운 Exception것과 당신이 잡은 것과 관련이 없다는 것을 알 수 있기 때문 입니다.

그러나 상황이 이상적이지 않다면 다음을 통해 컴파일러를 "트릭"할 수 있습니다.

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        ex2 = ex;
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

IMO ex2 = ex;는 다시 실패하지 않아야하지만 실패합니다.

이 경우에 컴파일 된 경우 javac 13+33


catch-block에서 catch 된 예외를 다시 할당하면 컴파일러가 똑똑하지 않다는 누군가의 링크를 읽었습니다. 이 경우 비슷한 것이 적용된다고 가정합니다. 컴파일러는 ex2예외가 발생하고 원래는로 작성 Exception되었지만에 다시 할당 ex되므로 컴파일러가 영리 할 수 ​​없음을 알고 있습니다.
Simon Forsberg

@SimonForsberg에 대한 열정이있는 사람 JLS이 와서이를 증명하는 데 필요한 인용문을 제공했을 것입니다. 불행히도 나는 그것들이 없습니다.
Eugene

레코드의 경우 catch 된 예외를 자체 ( ex = ex;) 로 재 할당하도록 catch 블록을 변경 하면 휴리스틱이 더 이상 적용되지 않습니다. 이 문제는 (11)를 통해 7에서 모든 소스 레벨에 적용 할 것으로 보인다 아마 13
Vogel612

질문도 살펴보십시오 . 이것과 가능한 dup의 dup이 그것을 설명하고 JLS에 링크합니다.
michalk
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.