finallyは、try-catch構文において、例外の有無や処置に限らずに行いたいことがある場合に指定する句であり、Javaの例外処理の柔軟性を高めます。プログラムが例外によって中断しても、catchによって捕捉されて続行しても、あるいは、正常に進んでも、finallyによって同等の処理を行うことができます。よって、例外が付き物の通信処理やファイル処理の後始末などに役立ちます。
しかし、finallyを用いると、通常のtry-catch構文の場合に比べて、動作が複雑になりますので、使うべき場面かどうかを考えるのが肝心です。 また、finallyを用いると動作テストが難しくなります。catchが1つしかない場合でも、下記の全パターンを試す必要があるからです。
- 例外が発生せずに進み、finallyの内容が実行されるパターン
- 例外が発生して、catchされ、その後でfinallyの内容が実行されるパターン
- 例外が発生したが、catchされず、finallyの内容が実行されてから例外終了となるパターン
finallyの中から外へ制御を移す処理は不可
そして、finallyの中から外へ制御を移す処理は、finallyの中で実行すべきではないので注意が必要です。上記のパターン3が正しく行われなくなってしまいます。具体的には、下記の文、メソッドが該当します。
- break、continue、return
- System.exit(int)
これらは、javacでコンパイルした場合にはエラーや警告の対象にはなりません。しかし、Eclipseを用いると、break、continue、returnについて「finallyブロックは正常に完了しません。」という警告が表示されます。下図はreturnの場合です。
ただし、System.exit(int)を使った場合や、break、continue、returnがif文などの中にある場合はチェックされません。警告に頼るのは危険です。
一例として、「例外の有無にかかわらず、ヒープメモリの消費量が20%を超えたら無条件に終了」することを意図したプログラムを作成しました。このプログラムでは、17行目からのfinallyの中で、breakを実行していますが、if文の中なので、警告が出ません。そして、下図のとおり実行すると、11行目にバグがあり、ゼロによる除算から例外が発生します。ところが、もしも、その前に、ヒープメモリの消費量が20%を超えていたら、19行目のbreakが実行され、例外が消されてしまうのです。
この例からも、finallyブロックが正常に完了しないプログラムは避けるべきことが分かります。
Copyright © ITmedia, Inc. All Rights Reserved.