2012-11-23 16 views
10

私は、インスタンスの初期化(ないクラスの初期化)ブロックで例外をスローしようとすると、私はエラーを取得する:Javaはそれ自体んがJavaインスタンスの初期化ブロックで例外をスローすることができないのはなぜですか?

initializer must be able to complete normally 

はそれが許されないのはなぜ?

次の例では、4つのクラスを作成します。クラスAは、ArithmeticExceptionのためにインスタンス化中に失敗します。これはcatchで処理できます。 Bと同じで、NullPointerExceptionで失敗します。しかし、私がCのように自分自身でNullPointerExceptionをスローしようとすると、プログラムはコンパイルされません。 Dのように私自身のRuntimeExceptionを定義しようとすると、同じエラーが発生します。したがって:

Javaと同じように私はどのようにすることができますか?

// -*- compile-command: "javac expr.java && java expr"; -*- 

class expr 
{ 
    class A 
    { 
     int y; 
     {{ y = 0/0; }} 
    } 

    class B 
    { 
     Integer x = null; 
     int y; 
     {{ y = x.intValue(); }} 
    } 

    class C 
    { 
     {{ throw new NullPointerException(); }} 
    } 

    class Rex extends RuntimeException {} 

    class D 
    { 
     {{ throw new Rex(); }} 
    } 

    void run() 
    { 
     try { A a = new A(); } 
     catch (Exception e) { System.out.println (e); } 

     try { B b = new B(); } 
     catch (Exception e) { System.out.println (e); } 

     try { C c = new C(); } 
     catch (Exception e) { System.out.println (e); } 

     try { D d = new D(); } 
     catch (Exception e) { System.out.println (e); } 
    } 

    public static void main (String argv[]) 
    { 
     expr e = new expr(); 
     e.run(); 
    } 
} 
+0

@AlexWienあなたはクラスとオブジェクトの違いを知っていますか? ;-) – ceving

+0

はい、インスタンスイニシャライザは存在しませんが、私は静的イニシャライザしか知りませんでした。 – AlexWien

答えて

13

initializer must be able to complete normally

は、例外をスローしないコードパスが必要であることを意味します。あなたの例は無条件に投げられ、したがって拒否されます。他の例では、静的解析は、すべての場合にスローされると判断するのに十分には行きません。例えば

public class StaticThrow { 
    static int foo = 0; 
    {{ if (Math.sin(3) < 0.5) { throw new ArithmeticException("Heya"); } else { foo = 3; } }} 
    public static void main(String[] args) { 
     StaticThrow t = new StaticThrow(); 
     System.out.println(StaticThrow.foo); 
    } 
} 

コンパイル、実行は、インスタンスが正しく初期化されていないであろうことを意味することに

Exception in thread "main" java.lang.ArithmeticException: Heya 
     at StaticThrow.<init>(StaticThrow.java:3) 
     at StaticThrow.main(StaticThrow.java:5) 
+0

'0/0'のコードパスはどこですか? – ceving

+4

コンパイラは、コードが常にスローされるのを見るために十分に解析しません。あなたの例では、 '{{何かを投げる; }} 'を静的な初期化子で使用すると、それは明らかです。常に真であるが、明白でない何かを試してみてください。 '{{if(Math.sin(3)<0。5){新しいArithmeticExceptionをスローします。 } else {何でも; }}} '。 –

+1

ありがとう! 'if(true)throw ...'でも十分です。 – ceving

5

は、Javaは、最小限の機能を持つように設計されており、そうする非常に良い理由がある場合に、複雑にのみ追加されます。 Javaは尋ねません。なぜ、それは尋ねる。私は本当にこれをサポートする必要がありますか?

初期化子ブロックのコードは、各コンストラクタに挿入する必要があり、コンパイラが正常に完了しないことがわかっているブロックをコンパイラが見つけにくいために。

このコードをコンパイルするようにコンパイラを作成することはできますが、そのコードを使用することはほとんどありません。


それは、この特定のケースであなたを助けにはなりませんが、それは便利

チェック例外を宣言する必要があり、そこに静的にチェック例外を宣言する方法はありませんか.....ということを知っていますインスタンスイニシャライザブロック

代わりに、チェックされた例外をキャッチしたり、処理したり、ラップすることができます。

+0

未確認の例外を作成する方法は? – ceving

+2

チェックされていない例外は 'RuntimeException'を拡張します。たとえば、 'IOException'のようにチェックされる例外を取る良い方法はありませんし、チェックをはずしてください。しかし、 'RuntimeException'を直接的または間接的に拡張する新しい型を作成すると、' throws'節を追加することなくそのインスタンスを投げることができます。 – cHao

1
{ throw new Rex(); } 

をスローします。インスタンスを適切に初期化できる条件がいくつかあります。例えば

{ if(true) { throw new Rex(); } } //It doesn't complain here 

例外がスローされた場合、あなたは、コンストラクタのthrows句に追加する必要があり、チェックインの例外です。例えば

public class MyObject { 
    { 
     //... 
      throw new Exception(); 
     //... 
    } 

    public MyObject() throws Exception { 

    } 
} 
2

あなたが実際に初期化ブロックで例外をスローするように許可されているが、あなたの例外をチェックものであれば、あなたは、「スロー」のキーワードですべてのコンストラクタをマークする必要があります。

あなたの例外は常にスローされる場合は、コンパイルエラーになりますが、このようなものは完全に合法です:

Fooクラス{

{{ 
    if(1 == 1) { 
     throw new Exception(); 
    } 
}} 

public Foo() throws Exception { 

} 

}

希望、これはいくつかを明確にもの。

1

The code inside an instance initializer may not return. Except in the case of anonymous inner classes, an instance initializer may throw checked exceptions only if the checked exceptions are explicitly declared in the throws clause of every constructor in the class. Instance initializers in anonymous inner classes, on the other hand, can throw any exception.

+0

匿名の内部クラスの_Instanceイニシャライザは、例外をスローすることができます。_ これは非常に小さな機能です。 – blueimpb

1

これは、Java言語仕様(Java SE 7)のsection 8.6でカバーされています。

It is a compile-time error if an instance initializer cannot complete normally (§14.21).

14.21は到達不能であることを定義します。

Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.

A break, continue, return, or throw statement cannot complete normally.

より複雑な分析が可能になります(まだ警告を生成することがありました)、特に注意が、これらは、一貫して実施可能に理解されている一連のルールであり、制限されることはありません。特に言語の将来の発展。

なぜ、(確かに)到達不能な文を含むプログラムを拒否したいのですか?なぜなら彼らはバグをほぼ確実に表しているからです(終了コード)。

到達不能なステートメントはありません。なぜインスタンスイニシャライザが正常に完了できる必要がありますか(インスタンス化不可能なクラスをサポートするためのコンストラクタの要件ではありません)。これは、Javaが合理的に単純なままであるためには行わない非ローカル解析を必要とし、保守中に再配置されたコードのステートメントが削除されるか、または順序が変わる可能性があるためです。

意見体系では、この比較的単純な分析と定義済みの割り当てルールでJavaが複雑すぎると考えていることは注目に値するでしょう。

関連する問題