source

Java는 정적 초기화 블록에서 선택된 예외를 발생시키는 것을 허용하지 않는 이유는 무엇입니까?

factcode 2023. 1. 29. 20:15
반응형

Java는 정적 초기화 블록에서 선택된 예외를 발생시키는 것을 허용하지 않는 이유는 무엇입니까?

Java는 정적 초기화 블록에서 선택된 예외를 발생시키는 것을 허용하지 않는 이유는 무엇입니까?이 디자인 결정의 배경은 무엇이었습니까?

소스에서는 이러한 체크된 예외를 처리할 수 없기 때문입니다.초기화 프로세스를 제어할 수 없으며 소스로부터 static{} 블록을 호출할 수 없으므로 시도 캐치로 둘러쌀 수 있습니다.

체크된 예외에 의해 나타나는 오류를 처리할 수 없으므로 체크된 예외의 스태틱블록을 투척할 수 없게 되었습니다.

정적 블록은 선택된 예외를 슬로우하지 않아야 하지만 여전히 체크되지 않은/런타임 예외를 슬로우할 수 있습니다.하지만 위와 같은 이유로 당신은 이것들도 처리할 수 없을 것입니다.

요약하면, 이 제한은 개발자가 애플리케이션을 복구할 수 없는 오류를 초래할 수 있는 무언가를 구축하는 것을 방지하거나 최소한 더 어렵게 만듭니다.

체크 마크가 붙어 있는 예외를 검출해, 체크 마크가 붙어 있지 않은 예외로서 재발송신하는 것으로, 문제를 회피할 수 있습니다.이 체크되지 않은 예외 클래스는 래퍼로서 기능합니다.

샘플 코드:

protected static class _YieldCurveConfigHelperSingleton {

    public static YieldCurveConfigHelper _staticInstance;

    static {
        try {
            _staticInstance = new YieldCurveConfigHelper();
        }
        catch (IOException | SAXException | JAXBException e) {
            throw new ExceptionInInitializerError(e);
        }
    }
}

다음과 같이 표시되어야 합니다(유효한 Java 코드가 아닙니다).

// Not a valid Java Code
static throws SomeCheckedException {
  throw new SomeCheckedException();
}

어디서 광고를 하겠습니까?선택한 예외에는 캐치가 필요합니다.클래스를 초기화할 가능성이 있는(또는 이미 초기화가 끝난 상태이기 때문에 그렇지 않은) 예를 몇 가지 생각해 보겠습니다.또, 그 복잡성에 주목하기 위해서, 예를 다른 스태틱인테라라이저에 넣습니다.

static {
  try {
     ClassA a = new ClassA();
     Class<ClassB> clazz = Class.forName(ClassB.class);
     String something = ClassC.SOME_STATIC_FIELD;
  } catch (Exception oops) {
     // anybody knows which type might occur?
  }
}

그리고 또 한 가지 끔찍한 일이 있어요

interface MyInterface {
  final static ClassA a = new ClassA();
}

ClassA에 체크된 예외가 발생하는 스태틱인테셜라이저가 있다고 상상해 주세요.이 경우 MyInterface('숨겨진' 스태틱 이니셜라이저가 있는 인터페이스)는 예외를 발생시키거나 처리해야 합니다(인터페이스에서의 예외 처리).그냥 놔두는 게 좋겠어.

Java는 정적 초기화 블록에서 선택된 예외를 발생시키는 것을 허용하지 않는 이유는 무엇입니까?

엄밀히 말하면, 당신은 할 수 있어단, 체크된 예외는 블록 내에서 포착해야 합니다.

Java의 실제 제약사항은 체크된 예외가 블록 밖으로 전파될 수 없다는 것입니다.

기술적으로는 체크되지 않은 예외를 스태틱인테셜라이저 블록1 밖으로 전파할 수도 있습니다.하지만 일부러 이렇게 하는 것은 정말 나쁜 생각이야!문제는 JVM 자체가 체크되지 않은 예외를 포착하고 이를 랩하여 재슬로우하는 것입니다.ExceptionInInitializerError.

의 : 그 nExceptionInInitializerError는 입니다.Error일반적인 예외는 아닙니다.회복하려고 하면 안 돼요.

대부분의 경우 예외를 검출할 수 없습니다.

public class Test {
    static {
        int i = 1;
        if (i == 1) {
            throw new RuntimeException("Bang!");
        }
    }
    
    public static void main(String[] args) {
        try {
            // stuff
        } catch (Throwable ex) {
            // This won't be executed.
            System.out.println("Caught " + ex);
        }
    }
}

$ java Test
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Bang!
    at Test.<clinit>(Test.java:5)

에도 없는 법이다.try ... catch상기의 경우ExceptionInInitializerError를 클릭합니다2.

이치를 들어, " " 를 경우 " " " " " " " 입니다.Class.forName(...)을 「」로 수 .try 중 .ExceptionInInitializerError 그 의 「」를 참조해 주세요.NoClassDefFoundError.

단, Restore를 복구하려고 하면ExceptionInInitializerError바리케이드에 부딪히기 쉽습니다.문제는 오류를 발생시키기 전에 JVM이 문제의 원인이 된 클래스를 "failed"로 표시한다는 것입니다.당신은 그것을 사용할 수 없을 것입니다.또한 실패한 클래스에 의존하는 다른 클래스도 초기화를 시도하면 실패한 상태가 됩니다.앞으로 유일한 방법은 실패한 클래스를 모두 언로드하는 것입니다.이것은 동적으로3 로드된 코드에 대해 실현 가능할 수 있지만 일반적으로 가능하지 않습니다.

1 - 정적 블록이 무조건 체크되지 않은 예외를 발생시키는 경우 컴파일 오류입니다.
2 - 수집되지 않은 기본 예외 핸들러를 등록하여 인터셉트할 수 있지만 "메인" 스레드를 시작할 수 없기 때문에 복구할 수 없습니다.
- 클래스를 클래스를 .3 - 실실, 、 3,er,,,,,, 。


이 디자인 결정의 배경은 무엇이었습니까?

프로그래머가 핸들러를 작성할 방법이 없기 때문에 처리할 수 없는 예외를 발생시키는 코드 쓰기로부터 프로그래머를 보호하기 위한 것입니다.

앞에서 설명한 바와 같이 스태틱인테셜라이저의 예외는 일반적인 어플리케이션을 벽돌로 바꿉니다.언어 설계자가 프로그래머에게 도움이 될 수 있는 최선의 방법은 체크된 케이스 1이 컴파일 오류임을 지정하는 것입니다.유감스럽게도 체크되지 않은 예외에 대해서도 이 작업을 수행하는 것은 실용적이지 않습니다.


그럼 스태틱 이니셜라이저에서 예외를 발생시키는 코드가 필요한 경우 어떻게 해야 합니까?기본적으로 다음 두 가지 대안이 있습니다.

  • 블록내의 예외로부터(풀!) 회복이 가능한 경우는, 그렇게 합니다.

  • 그렇지 않으면 정적 초기화 블록(또는 정적 변수의 이니셜라이저)에서 초기화가 발생하지 않도록 코드를 재구성하십시오.일반 스레드에서 호출할 수 있는 메서드 또는 생성자에 넣습니다.

Java Language Specifications(Java 언어 사양)를 참조하십시오.스태틱 이니셜라이저의 경우 컴파일 시간 오류라고 기재되어 있습니다. 실패하다 체크 마크가 켜져 있는 예외를 제외하고 갑자기 완료될 수 있습니다.

작성한 코드가 스태틱 초기화 블록을 호출할 수 없으므로 체크박스를 켜면 도움이 되지 않습니다.exceptions가능한 경우 체크된 예외가 발생했을 때 jvm은 어떻게 처리합니까? Runtimeexceptions전파됩니다.

예: Spring의 DispatcherServlet(또는 springframework).web.servlet.DispatcherServlet)은 체크된 예외를 검출하여 다른 체크되지 않은 예외를 슬로우하는 시나리오를 처리합니다.

static {
    // Load default strategy implementations from properties file.
    // This is currently strictly internal and not meant to be customized
    // by application developers.
    try {
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    }
    catch (IOException ex) {
        throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
    }

체크 마크를 붙인 예외 투척을 컴파일 할 수 있습니다.

static {
    try {
        throw new IOException();
    } catch (Exception e) {
         // Do Something
    }
}

언급URL : https://stackoverflow.com/questions/2070293/why-doesnt-java-allow-to-throw-a-checked-exception-from-static-initialization-b

반응형