Previous | Next | Trail Map | Writing Java Programs | 例外を使用したエラー処理


finally ブロック

例外ハンドラの作成の手順の最後は、制御がプログラムの別の部分に渡る前に、メソッドの状態の後始末を行なう機構を提供することである。finally ブロック内に後始末を行なうコードを組み込むことによって、この作業を行う。

今まで学習してきたwriteList() メソッドの try ブロックは、PrintStream を開く。 プログラムは制御が writeList() メソッドから他に渡る前に、そのストリームを閉じるべきである。writeList() try ブロックには、3つの異なる終了の可能性があるので、これによって幾分複雑な問題が持ち上がる。

  1. new FileOutputStream 文が失敗して、IOException をあげた。
  2. victor.elementAt(i) 文が失敗して、 ArrayIndexOutOfBoundsException をあげた。
  3. すべてが成功して、 try ブロックが正常に終了した。

ランタイムシステムは、 try ブロック内で何が起きるかにかかわらず、常にfinally ブロック内の命令を実行する。 つまり、上記に表示したシナリオ1、2、3のどのシナリオによって、制御が writeList() メソッドの try ブロックを終了するかどうかにかかわらず、 finally ブロック内のコードは実行される。

writeList() メソッドの finally ブロックを次に示す。 finallyブロックは後始末を行って、 PrintStream を閉じる。

finally {
    if (pStr != null) { 
        System.out.println("Closing PrintStream");
        pStr.close(); 
    } else { 
        System.out.println("PrintStream not open");
    } 
}
 

finally 文は本当に必要であるか?

最初は finally 文の必要性は、すぐにはわからないかもしれない。 プログラマは、しばしば「 finally 文が本当に必要であるかとか、それは Java コーヒーのための砂糖みたいなものか?」と疑問に思う。 特に C++ ではfinally 文を使わないので、 C++ プログラマはその必要性を疑う。

finally 文の必要性は、次のことを考慮するまで明白ではない。もし ArrayIndexOutOfBoundsException の例外ハンドラを用意しないで、ArrayIndexOutOfBoundsException が発生したら、 writeList() メソッド中の PrintStream はどうやって閉じるのか? (ArrayIndexOutOfBoundsException の例外はランタイム例外であり、コンパイラは writeList() が例外をあげる可能性のあるメソッド呼び出しを含むとは警告しないので、ハンドラを除くことは容易で、しかも正当である。) 答えは、もし ArrayIndexOutOfBoundsException が発生し、 writeList() がそのためのハンドラを用意していない場合は、writeList()finally 文を用意しない限り、PrintStream は閉じられない。

finally 文を使用することには他にも利点がある。 writeList()の例で、 finally 文の介入無しで後始末処理を用意することができる。 例えば以下に示すように、 tryブロックの終わりに PrintStream を閉じるコードを置き、 ArrayIndexOutOfBoundsException の例外ハンドラ内にも同じコードを配置することができる。

try {
    . . .
    pStr.close();       // don't do this; it duplicates code 
} catch (ArrayIndexOutOfBoundsException e) {
    pStr.close();       // don't do this; it duplicates code 
    System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
    System.err.println("Caught IOException: " + e.getMessage());
}

しかし、これはコードを繰り返すのでコードが読みにくく、後でコードを修正した場合、エラーが発生し易くなる。 例えば、新しい型の例外をあげるコードを try ブロックに追加する場合、新規の例外ハンドラ内で PrintStream を忘れずに閉じること。


Previous | Next | Trail Map | Writing Java Programs | 例外を使用したエラー処理