IT

Java 8의 예외 유형 추론의 독특한 기능

lottoking 2020. 9. 25. 08:19

Java 8의 예외 유형 추론의 독특한 기능


이 사이트에서 다른 답변에 대한 코드를 작성하는 동안 다음과 같은 특징을 발견했습니다.

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    //no problems here
  nonSneakyThrow(e); //ERRROR: Unhandled exception: java.lang.Exception
}

@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

static <T extends Throwable> void nonSneakyThrow(T t) throws T {
  throw t;
}

첫째, 왜 sneakyThrow호출이 컴파일러에 대해 괜찮은지 혼란 스럽습니다 . T확인되지 않은 예외 유형에 대한 언급이 없는 경우 가능한 유형은 무엇입니까?

둘째, 작동한다는 것을 이것이 받아들이-plane 왜 컴파일러가 nonSneakyThrow호출 에 대해 불평 합니까? 그들은 매우 존경합니다.


의 T는 sneakyThrow로 추론 RuntimeException됩니다. 유형 추론에 대한 언어 사양 ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html ) 에서 따를 수 있습니다.

첫째, 섹션 18.1.3에 메모가 있습니다.

양식의 경계 throws α는 순전히 정보 제공 용입니다. 가능한 경우 확인 된 예외 유형이 아니도록 α의 인스턴스화를 최적화하도록 해결을 지시합니다.

이것은 아무 영향도 없지만 특별한 경우에 유추 된 예외 유형에 대한 자세한 정보를 제공하는 해상도 섹션 (18.4)을 알려줍니다.

... 그렇지 않으면 결합 세트가 포함되어있는 경우 throws αi, 및 αi 적절한 상한은 기껏해야하고, Exception, Throwable, 및 Object, 그때의 티 = RuntimeException.

이 경우에 적용됩니다 sneakyThrow- 상한은 유일한 Throwable이므로 사양에 따라 T추정 RuntimeException되므로 컴파일됩니다. 방법의 본문은 중요하지 않습니다. 확인되지 않았으므로 실행에 성공하여 타임 체크 예외 시스템을 무효화합니다.

nonSneakyThrow방법 의이 같은 그 컴파일되지 않습니다 T낮은의 하한 가지고있다 Exception(즉 T의 슈퍼해야 우리한다 Exception, 또는 Exception그이, 그래서 그것 때문에이 호출되고있는 유형으로, 체크 예외 인 자체) T로 추정됩니다 Exception.


유형 추론이 유형 변수에 대해 단일 상한을 생성하는 경우 일반적으로 상한이 솔루션으로 선택됩니다. 예를 들어이면 T<<Number해는 T=Number입니다. Integer, Float등도 제약보기 조건을 충족 할 수 있지만 대신 선택할 이유가 없습니다 Number.

즉, 위해도의 경우와 throws T자바 5-7 : T<<Throwable => T=Throwable. (Sneaky throw 솔루션은 모두 명시 적 <RuntimeException>유형 인수가 해당, 즉 이름 추론 <Throwable>됩니다.)

java8에서는 람다가 도입되는 문제가 있습니다. 이 경우를 고려하십시오

interface Action<T extends Throwable>
{
    void doIt() throws T;
}

<T extends Throwable> void invoke(Action<T> action) throws T
{
    action.doIt(); // throws T
}    

빈 람다로 호출하면 T무엇으로 추론을 호출합니까?

    invoke( ()->{} ); 

에 대한 유일한 제약 T은 상한 Throwable입니다. java8의 초기 단계에서는 T=Throwable추론됩니다. 제출 내가 한이 보고서를 참조하십시오 .

그러나 이것은 Throwable빈 블록에서 확인 된 예외 를 추론하기에는 꽤 어리석은 일 입니다. 보고서에서 제안이 제안되었습니다 (JLS에서 제안한 제안)-

If E has not been inferred from previous steps, and E is in the throw clause, 
and E has an upper constraint E<<X,
    if X:>RuntimeException, infer E=RuntimeException
    otherwise, infer E=X. (X is an Error or a checked exception)

즉, 상한이 Exception또는 Throwable인 경우 RuntimeException솔루션으로 선택 합니다. 경우가이 있다 상한의 특정 하위 유형을 선택하는 좋은 이유.


사용를 sneakyThrow하면 유형 T특정 유형이 없는 제한된 제네릭 유형 변수입니다 (유형의 출처가 없기 때문에).

사용을 nonSneakyThrow하면 유형 T이 인수와 동일한 유형이므로 예제에서 TnonSneakyThrow(e);Exception입니다. 으로는 testSneaky()던져 선언하지가 않는 Exception오류가-display됩니다.

이것은 확인 된 예외가있는 Generics의 알려진 간섭입니다.

참고 URL : https://stackoverflow.com/questions/31316581/a-peculiar-feature-of-exception-type-inference-in-java-8