168

Java Language Sepecification 、第 3 版によると:

ジェネリック クラスが の直接または間接のサブクラスである場合、コンパイル時エラーになりますThrowable

この決定がなされた理由を理解したいと思います。一般的な例外の何が問題になっていますか?

(私の知る限り、ジェネリックはコンパイル時のシンタックス シュガーにすぎずObject.classファイル内で変換されるため、ジェネリック クラスを効果的に宣言することは、その中のすべてがObject. .)

4

6 に答える 6

174

マークが言ったように、型は具体化できません。これは、次の場合に問題になります。

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

SomeException<Integer>との両方SomeException<String>が同じタイプに消去されます。JVM が例外インスタンスを区別する方法がないため、どのcatchブロックを実行する必要があるかを判断する方法がありません。

于 2009-02-01T18:22:42.257 に答える
16

例外の使用方法の簡単な例を次に示します。

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

例外をパラメトリックにすることはできないため、構文は制限されているため、型は識別子として記述し、後続のパラメーターは指定しないでください。

于 2009-02-01T18:11:05.417 に答える
2

パラメータ化を保証する方法がないためだと思います。次のコードを検討してください。

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

お気づきのように、パラメータ化は単なる構文糖衣です。ただし、コンパイラは、コンパイル スコープ内のオブジェクトへのすべての参照で、パラメーター化が一貫していることを確認しようとします。例外が発生した場合、コンパイラには、処理中のスコープからのみ MyException がスローされることを保証する方法がありません。

于 2009-02-01T18:12:12.670 に答える