programing

Java는 왜 Throwable의 범용 서브클래스를 허용하지 않는가?

randomtip 2022. 7. 14. 21:11
반응형

Java는 왜 Throwable의 범용 서브클래스를 허용하지 않는가?

Java Language Sepecification에 따르면 제3판:

시 입니다.Throwable.

나는 왜 이 결정이 내려졌는지 이해하고 싶다.일반적인 예외에 무슨 문제가 있습니까?

타임됩니다.또한 번역됩니다.Object anyway anyway the the the .class 즉 은, 그이 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」라고 하는 것과 같습니다.Object))))))) 。

마크의 설명대로 타입은 재작성할 수 없습니다.이것은 다음과 같은 경우에 문제가 됩니다.

try {
   doSomeStuff();
} catch (SomeException<Integer> e) {
   // ignore that
} catch (SomeException<String> e) {
   crashAndBurn()
}

다.SomeException<Integer> ★★★★★★★★★★★★★★★★★」SomeException<String>되어 있기 수 어떤 JVM이 어떤 JVM인지 알 수.catch블록을 실행해야 합니다.

다음은 예외를 사용하는 간단한 예입니다.

class IntegerExceptionTest {
  public static void main(String[] args) {
    try {
      throw new IntegerException(42);
    } catch (IntegerException e) {
      assert e.getValue() == 42;
    }
  }
}

TRy 문의 본문은 지정된 값과 함께 예외를 슬로우합니다.이 값은 catch 구에 의해 포착됩니다.

반면 다음과 같은 새로운 예외 정의는 매개 변수화된 유형을 생성하므로 금지됩니다.

class ParametricException<T> extends Exception {  // compile-time error
  private final T value;
  public ParametricException(T value) { this.value = value; }
  public T getValue() { return value; }
}

위의 컴파일을 시도하면 다음 오류가 보고됩니다.

% javac ParametricException.java
ParametricException.java:1: a generic class may not extend
java.lang.Throwable
class ParametricException<T> extends Exception {  // compile-time error
                                     ^
1 error

유형을 다시 작성할 수 없기 때문에 이러한 예외를 포착하는 시도는 거의 실패해야 하므로 이 제한은 합리적입니다.일반적으로 다음과 같은 예외를 사용할 수 있습니다.

class ParametricExceptionTest {
  public static void main(String[] args) {
    try {
      throw new ParametricException<Integer>(42);
    } catch (ParametricException<Integer> e) {  // compile-time error
      assert e.getValue()==42;
    }
  }
}

catch 절의 유형은 다시 작성할 수 없으므로 허용되지 않습니다.이 글을 쓸 때 Sun 컴파일러는 다음과 같은 경우에 일련의 구문 오류를 보고합니다.

% javac ParametricExceptionTest.java
ParametricExceptionTest.java:5: <identifier> expected
    } catch (ParametricException<Integer> e) {
                                ^
ParametricExceptionTest.java:8: ')' expected
  }
  ^
ParametricExceptionTest.java:9: '}' expected
}
 ^
3 errors

예외는 파라미터로 할 수 없기 때문에 구문은 제한되므로 타입을 다음 파라미터 없이 식별자로 기술해야 합니다.

기본적으로 디자인이 안 좋아서 그래요.

이 문제는 다음과 같은 깔끔한 추상 설계를 방해합니다.

public interface Repository<ID, E extends Entity<ID>> {

    E getById(ID id) throws EntityNotFoundException<E, ID>;
}

제네릭스를 위한 캐치 조항이 실패한다는 사실이 입증되지 않았다는 것은 그것에 대한 변명이 없다.컴파일러는 단순히 슬로우 가능 또는 캐치 구 내의 제네릭스를 확장하는 구체적인 제네릭 유형을 허용하지 않을 수 있습니다.

제네릭은 컴파일 시에 타입이 올바른지 여부를 확인합니다.그런 다음 일반 유형 정보는 유형 삭제라고 하는 프로세스에서 제거됩니다.예를들면,List<Integer>non-timeout 타입으로 변환됩니다.List.

유형 삭제로 인해 런타임에 유형 매개 변수를 확인할 수 없습니다.

예를 들어, 당신이 다음 단계를 연장하는 것이 허용된다고 가정해 봅시다.Throwable다음과 같습니다.

public class GenericException<T> extends Throwable

이제 다음 코드를 살펴보겠습니다.

try {
    throw new GenericException<Integer>();
}
catch(GenericException<Integer> e) {
    System.err.println("Integer");
}
catch(GenericException<String> e) {
    System.err.println("String");
}

유형 삭제로 인해 실행 시 어떤 catch 블록을 실행할지 알 수 없습니다.

따라서 일반 클래스가 Throwable의 직접 또는 간접 서브 클래스인 경우 컴파일 시 오류가 발생합니다.

출처: 유형 삭제 문제

파라메타화를 보장할 방법이 없기 때문이라고 생각합니다.다음 코드를 고려합니다.

try
{
    doSomethingThatCanThrow();
}
catch (MyException<Foo> e)
{
    // handle it
}

아시다시피 파라미터화는 통사적인 설탕일 뿐입니다.그러나 컴파일러는 컴파일 범위 내의 오브젝트에 대한 모든 참조에서 파라미터화가 일관되게 유지되도록 합니다.예외의 경우 컴파일러는 MyException이 처리 중인 범위에서만 느려지는 것을 보증할 수 없습니다.

질문과는 그다지 관련이 없지만, 정말 원하는 것은inner class을 확장하다Throwable선언할 수 있다static이것은, 다음의 경우에 적용할 수 있습니다.Throwable는 논리적으로 인클로징클래스와 관련되어 있지만 해당 인클로징클래스의 특정 범용 타입과는 관계가 없습니다.선언함으로써static, 이것은 인클로징 클래스의 인스턴스에 바인드 되어 있지 않기 때문에, 문제는 해소됩니다.

다음의 예(인정적으로는 그다지 좋지 않습니다)는, 이것을 나타내고 있습니다.

/** A map for <String, V> pairs where the Vs must be strictly increasing */
public class IncreasingPairs<V extends Comparable<V>> {

    private final Map<String, V> map;

    public IncreasingPairs() {
        map = new HashMap<>();
    }

    public void insertPair(String newKey, V value) {
        // ensure new value is bigger than every value already in the map
        for (String oldKey : map.keySet())
            if (!(value.compareTo(map.get(oldKey)) > 0))
                throw new InvalidPairException(newKey, oldKey);

        map.put(newKey, value);
    }

    /** Thrown when an invalid Pair is inserted */
    public static class InvalidPairException extends RuntimeException {

        /** Constructs the Exception, independent of V! */
        public InvalidPairException(String newKey, String oldKey) {
            super(String.format("Value with key %s is not bigger than the value associated with existing key %s",
                    newKey, oldKey));
        }
    }
}

자세한 것은, docs.oracle.com 를 참조해 주세요.

언급URL : https://stackoverflow.com/questions/501277/why-doesnt-java-allow-generic-subclasses-of-throwable

반응형