문제

나는 Exception.fillInStackTrace가 Exception 또는 파생된 Exception 객체를 반환해야 한다고 생각합니다.아래 두 가지 기능을 고려하면,

public static void f() throws Throwable {
    try {
        throw new Throwable();
    } catch (Exception e) {
        System.out.println("catch exception e");
        e.printStackTrace();
    } 
}
public static void g() throws Throwable {
    try {
        try {
            throw new Exception("exception");
        } catch (Exception e) {
            System.out.println("inner exception handler");
            throw e.fillInStackTrace();
        }
    } catch (Exception e) {
        System.out.println("outer exception handler");
        e.printStackTrace();
    }
}
  1. 그만큼 exception handler 잡을 수 없었다 new Throwable() 첫 번째 기능에서 f().
  2. 그만큼 exception handler 잡을 수 있었다 e.fillInstackTrace() 두 번째 기능에서 g().
  3. 하지만 두 번째 기능 g() 아직은 그럴 필요가 있겠지 throws Throwable.이건 정말 이상해요. e.fillInstackTrace().

그래서 내 질문은 왜 이상한 구문을 개발하는 대신 Exception.fillInStackTrace가 Exception 또는 Exception-derived를 반환하지 않는 것입니까?

편집하다:
에게 밝히다 내 질문:"이상한 구문"이 의미하는 바는 다음과 같습니다.

  1. 부터 Exception.fillInStackTrace() 반품 Throwable 참조, 수신한 예외 처리기 Exception 참조는 예외를 포착할 수 없어야 합니다. Java는 암시적 다운캐스트를 허용하지 않기 때문에 다음과 같아야 합니다. return (Exception)e.fillInstackTrace().
  2. 예외 처리기가 수신하도록 설계되었기 때문에 Exception 참조가 처리할 수 있습니다. Throwable 예외, 메서드를 표시할 필요가 없습니다. g() 던진다 Throwable 예외입니다. 하지만 자바 컴파일러는 그렇게 하도록 강제합니다.

감사해요.

도움이 되었습니까?

해결책

실제로 질문 2부터 시작하여 질문에 대답하는 것이 더 쉽습니다.

귀하는 다음과 같이 질문했습니다.2.Exception 참조를 수신하는 예외 핸들러가 Throwable 예외를 처리할 수 있도록 설계되었으므로 g() 메소드가 Throwable 예외를 던지는 것을 표시할 필요가 없습니다. 그러나 Java 컴파일러는 그렇게 하도록 강제합니다.

답변:실제로 catch(Exception e)는 Throwable을 잡을 수 없습니다.이 시도:

try {
       Throwable t = new Throwable();
       throw t.fillInStackTrace();
} catch (Exception e) {
    System.out.println("outer exception handler");
    e.printStackTrace();
} 

이 경우에는 catch 절이 던지기를 포착하지 않는다는 것을 알 수 있습니다.

g() 메소드에서 catch 절이 작동하는 이유는 throw e.fillInStackTrace(), fillInStackTrace 호출은 실제로 예외를 반환합니다(e가 예외 자체이기 때문입니다).Exception은 Throwable의 하위 클래스이므로 fillInStackTrace 선언과 모순되지 않습니다.

이제 첫 번째 질문으로 넘어갑니다

귀하는 다음과 같이 질문했습니다.1.Exception.fillInStackTrace()는 Throwable 참조를 반환하므로 Exception 참조를 수신하는 예외 핸들러는 예외를 포착할 수 없어야 합니다. Java는 암시적 다운캐스트를 허용하지 않기 때문에 return(Exception)e.fillInstackTrace()와 유사해야 합니다.

답변:이는 암묵적인 다운캐스트가 아닙니다.이것을 과부하의 변형으로 생각하십시오.

당신이 가지고 있다고 가정 해 봅시다

void process(Throwable t){
   ...
}
void process(Exception e){
  ...
} 

전화하면 process(someObject), 첫 번째 또는 두 번째 프로세스 메서드가 호출되는지 여부는 런타임에 결정됩니다.마찬가지로, catch(Exception e) 절이 throw를 포착할 수 있는지 여부는 Exception을 throw하는지 Throwable을 throw하는지에 따라 런타임에 결정됩니다.

다른 팁

나는 당신의 질문에 오히려 의아해합니다.Java 예외/예외 처리에 대해 이해하지 못하는 부분이 분명히 있습니다.그럼 처음부터 시작해 보겠습니다.

Java에서 모든 예외(이 용어가 Java 언어 사양에서 사용된다는 의미에서)는 다음의 하위 클래스인 일부 클래스의 인스턴스입니다. java.lang.Throwable.Throwable의 직접 하위 클래스는 두 개(단지 두 개)입니다.즉. java.lang.Exception 그리고 java.lang.Error.이 모든 클래스의 인스턴스...Throwable 및 Error 인스턴스를 포함하여 ...JLS에서는 예외라고 합니다.

예외 처리기는 JLS 의미에서 사용된 예외 유형과 할당 호환되는 예외를 포착합니다. catch 선언.예를 들면 다음과 같습니다.

try {
    ....
} catch (Exception ex) {
    ...
}

에서 발생한 모든 예외를 포착합니다. try 인스턴스인 블록 java.lang.Exception 또는 직접적이거나 간접적인 하위 유형의 java.lang.Exception.하지만 다음 인스턴스를 포착하지 못합니다. java.lang.Throwable, 왜냐하면 그것은 (분명히) 위의 사항 중 하나가 아니기 때문입니다.

반면에:

try {
    ....
} catch (Throwable ex) {
    ...
}

~ 할 것이다 인스턴스를 포착하다 java.lang.Throwable.

이에 비추어 귀하의 예를 검토해 보면, 왜 f 메소드가 Throwable 인스턴스를 포착하지 않습니다.catch 절의 예외 유형과 일치하지 않습니다!대조적으로, g Exception 인스턴스가 catch 절의 예외 유형과 일치하므로 catch됩니다.

던질 수 있는 물건을 던져야 한다는 말을 이해하지 못합니다. g.첫째, 메소드가 Throwable을 던진다고 선언한다는 사실 하지 않습니다 실제로 던져야 한다는 뜻입니다.그것이 말하는 전부는 그것이다. ~할 것 같다 Throwable에 할당 가능한 것을 던지십시오 ...아마도 향후 버전에서는 g 방법.둘째, 추가한다면 throw e; 외부 캐치 블록에 ~일 것이다 Throwable에 할당할 수 있는 것을 던지고 있어야 합니다.

마지막으로 Throwable, Exception, Error 및 RuntimeException의 인스턴스를 생성하는 것은 일반적으로 좋지 않은 생각입니다.그리고 언제, 어떻게 잡는지 매우 조심해야 합니다.예를 들어:

try {
     // throws an IOException if file is missing
    InputStream is = new FileInputStream("someFile.txt");
    // do other stuff
} catch (Exception ex) {
    System.err.println("File not found");
    // WRONG!!!  We might have caught some completely unrelated exception;
    // e.g. a NullPointerException, StackOverflowError, 
}

편집하다 - OP의 의견에 대한 답변:

하지만 내가 던진 것은 throw e.fillInStackTrace();예외가 아닌 Throwable의 인스턴스여야 합니다!

Javadoc에서는 반환된 객체가 메소드를 호출하는 예외 객체라고 구체적으로 말합니다.목적 fillInStacktrace() 방법은 기존 개체에 대한 스택 추적을 채우는 것입니다.다른 예외를 원하면 다음을 사용해야 합니다. new 하나를 만들려면.

실제로, 외부 예외 핸들러는 throw e.fillInStackTrace()에 의해 던져진 Throwable을 포착해서는 안 된다는 뜻입니다.

왜 그런지 설명했습니다. 왜냐하면 Throwable은 실제로 원래의 예외이기 때문입니다.내 설명에 당신이 이해하지 못하는 부분이 있나요? 아니면 단순히 Java가 정의된 방식이 마음에 들지 않는다는 뜻인가요?

편집 2

그리고 외부 예외 처리기가 Throwable 예외를 처리할 수 있다면 왜 g 메소드가 Throwable 예외를 발생시키도록 지정해야 합니까?

내 말을 오해하셨네요...즉, 예외를 발생시킨 경우 throws Throwable 중복되지 않습니다.OTOH, 마침내 귀하의 불만을 이해한 것 같습니다.

귀하의 불만 사항의 ​​핵심은 다음과 같이 컴파일 오류가 발생한다는 것입니다.

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw ex.fillInStackTrace();
        // according to the static type checker, the above throws a Throwable
        // which has to be caught, or declared as thrown.  But we "know" that the 
        // exception cannot be anything other than an Exception.
    }
}

나는 이것이 다소 예상치 못한 일임을 알 수 있습니다.그러나 그것은 피할 수 없는 일이다.서명을 선언할 수 있는 방법은 없습니다(Java 유형 시스템의 주요 변경이 부족함). fillInStacktrace 그것은 모든 경우에 작동합니다.예를 들어 메서드 선언을 Exception 클래스로 이동한 경우 Exception 하위 유형에 대해 동일한 문제를 반복하게 됩니다.그러나 일반 유형 매개변수를 사용하여 서명을 표현하려고 하면 Throwable의 모든 하위 클래스를 명시적인 일반 유형으로 만드는 것이 수반됩니다.

다행히 치료법은 정말 간단합니다.결과를 캐스팅하다 fillInStacktrace() 다음과 같이:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw (Exception) (ex.fillInStackTrace());
    }
}

그리고 마지막 요점은 애플리케이션이 명시적으로 호출하는 것이 매우 드물다는 것입니다. fillInStacktrace().그런 점에서 볼 때, Java 설계자가 이 문제를 해결하려고 "힘을 다해" 노력하는 것은 전혀 가치가 없었을 것입니다.특히나 정말 사소한 불편함에 불과하기 때문에...많으면.

내 생각엔 Frank Yellin에게 물어봐야 할 것 같아요. @author ~의 java.lang.Exception).다른 사람들이 말했듯이, fillInStackTrace() 에 선언되어 있습니다 Throwable 그리고 반환 문서화 this, 이므로 반환 유형은 다음과 같아야 합니다. Throwable.그것은 단지 상속받은 것입니다. Exception.Frank는 그것을 재정의할 수 있었습니다. Exception, 이와 같이:

public class Exception extends Throwable{
    /**Narrows the type of the overridden method*/
    @Override
    public synchronized Exception fillInStackTrace() {
        super.fillInStackTrace();
        return this;
    }
}

...하지만 그는 그러지 않았습니다.Java 1.5 이전에는 컴파일 오류가 발생했기 때문입니다.1.5 이상에서는 공변 반환 유형 허용된다 위의 내용은 합법적입니다.

하지만 내 생각엔 위의 재정의가 존재한다면 왜 그런 것인지 묻게 될 것입니다. RuntimeException 유사한 재정의가 없는 이유는 무엇입니까? ArrayStoreException 해당 재정의를 재정의하지 않습니다.그래서 Frank와 친구들은 아마도 수백 개의 동일한 재정의를 작성하고 싶지 않았을 것입니다.

자신만의 사용자 정의 예외 클래스를 처리하는 경우 다음을 쉽게 재정의할 수 있다는 점은 주목할 가치가 있습니다. fillinStackTrace() 위에서 했던 것처럼 방법을 사용하고 원하는 더 좁은 유형을 얻으세요.

제네릭을 사용하면 다음 선언을 확장하는 것을 상상할 수 있습니다. Throwable 에게:

public class Throwable<T extends Throwable<T>>{
    public synchronized native T fillInStackTrace();
}

...하지만 이는 이 답변의 범위를 벗어나는 이유로 인해 실제로 만족스럽지 않습니다.

fillInStackTrace 동일한 객체에 대한 참조를 반환합니다.다시 던지는 것을 허용하는 메소드 체이닝입니다. Exception 예외의 스택 추적을 재설정합니다.

public static void m() {
    throw new RuntimeException();

}

public static void main(String[] args) throws Throwable {
    try {
        m();
    } catch (Exception e) {
        e.printStackTrace();
        throw e.fillInStackTrace();
    }
}

메소드 반환 유형은 기본 유형만 될 수 있습니다. Throwable.메서드가 매개변수화된 형식을 반환하도록 생성될 수 있습니다.하지만 지금은 그렇지 않습니다.

RuntimeException e = new RuntimeException();
Throwable e1 = e.fillInStackTrace();
System.out.println(e1.getClass().getName()); //prints java.lang.RuntimeException
System.out.println(e == e1); //prints true

fillInStackTrace() 에 의해 정의됩니다 Throwable, 아니다 Exception.

모든 하위 클래스는 아닙니다. Throwable 예외입니다(Error, 예를 들어).한 Throwable 반환 값에 대해 보장할 수 있는 유일한 것은 fillInStackTrace() 그것이 바로 그 예이다. Throwable (단지 동일한 객체를 반환하기 때문에 찬드라 파트니 유명한).

실제로 fillInStackTrace 호출된 것과 동일한 객체를 반환합니다.

e.fillInStackTrace == e 항상 사실이다

그것은 단지 지름길, 그냥 쓸 수도 있습니다

    } catch (Exception e) {
        System.out.println("inner exception handler");
        e.fillInStackTrace();
        throw e;
    }

아니면 캐스트를 사용하세요

    throw (Exception) e.fillInStackTrace();

그런데, 같은 일이 일어납니다. initCause().

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top