JavaやC#など、オブジェクト指向言語の中には「finally」処理を行える言語もあります。
finally 処理とは、例外処理が起きようが起きまいが最後に必ず実行する処理のことで、tryやcatchと合わせて「try-catch-finally 構文」と呼ばれることもあります。
さて try-catch-finally 構文は以下のような書式になります。
1ページ目に示した例外処理書式との違いは最後に「finally」が付いている点だけです。
try
{
例外1〜Nが起きる可能性のある処理部
}
catch(例外その1){
{
例外1のエラー処理部
}
catch(例外その2){
{
例外2のエラー処理部
}
・・・
catch(例外そのN){
{
例外Nのエラー処理部
}
finally{
最後に必ず実行する処理部
}
finally にはいろいろな使い道がありますが、特にリソースの開放など後始末をしたい時によく使われます。
例えばメソッド内で複数のファイルをオープンする時、もし途中でファイルオープンに失敗したら既に開いているファイルについてはクローズしたいという状況を考えましょう。
まず finally を使わない場合のソースと実行例を示します。
import java.io.FileReader;
import java.io.IOException;
public class Main
{
public static void test(){
FileReader in1 = null;
FileReader in2 = null;
try{
// ファイルのオープン処理
in1 = new FileReader( "hoge.txt" );
in2 = new FileReader( "fuga.txt" );
// ファイルのクローズ処理
if( in1 != null ){
System.out.println( "hoge.txt を閉じます" );
in1.close();
}
if( in2 != null ){
System.out.println( "fuba.txt を閉じます" );
in2.close();
}
}
catch( IOException e ) {
System.out.println( e );
return;
}
}
public static void main(String[] args) {
test();
}
}
実行結果:
※ hoge.txt はあるけど fuga.txt は無いという状況で実行
java.io.FileNotFoundException: fuga.txt (そのようなファイルやディレクトリはありません)
上の例では fuga.txt をオープンしようとすると例外が発生して catch 内に飛んでしまうため既に開いている hoge.txt はクローズされていません。
ではファイルのオープン処理とクローズ処理を分離して書いたらどうなるでしょうか?
import java.io.FileReader;
import java.io.IOException;
public class Main
{
public static void test(){
FileReader in1 = null;
FileReader in2 = null;
try{
// ファイルのオープン処理
in1 = new FileReader( "hoge.txt" );
in2 = new FileReader( "fuga.txt" );
}
catch( IOException e ) {
System.out.println( e );
return;
}
try{
// ファイルのクローズ処理
if( in1 != null ){
System.out.println( "hoge.txt を閉じます" );
in1.close();
}
if( in2 != null ){
System.out.println( "fuba.txt を閉じます" );
in2.close();
}
}
catch( IOException e ) {
System.out.println( e );
return;
}
}
public static void main(String[] args) {
test();
}
}
実行結果:
※ hoge.txt はあるけど fuga.txt は無いという状況で実行
java.io.FileNotFoundException: fuga.txt (そのようなファイルやディレクトリはありません)
この場合も hoge.txt はクローズされていません。
何故かというと fuga.txt のオープンに失敗すると最初の catch文の中で return してメソッドから抜けてしまっているからです。
そこでファイルのクローズ処理を finally 内に移動してみます。
import java.io.FileReader;
import java.io.IOException;
public class Main
{
public static void test(){
FileReader in1 = null;
FileReader in2 = null;
try{
// ファイルのオーブン処理
in1 = new FileReader( "hoge.txt" );
in2 = new FileReader( "fuga.txt" );
}
catch( IOException e ) {
System.out.println( e );
return;
}
finally{
try{
// ファイルのクローズ処理を分離
if( in1 != null ){
System.out.println( "hoge.txt を閉じます" );
in1.close();
}
if( in2 != null ){
System.out.println( "fuba.txt を閉じます" );
in2.close();
}
}
catch( IOException e ) {
System.out.println( e );
return;
}
}
}
public static void main(String[] args) {
test();
}
}
実行結果:
※ hoge.txt はあるけど fuga.txt は無いという状況で実行
java.io.FileNotFoundException: fuga.txt (そのようなファイルやディレクトリはありません)
hoge.txt を閉じます
finally の中にさらに try-catch があるため若干見づらいソースコードになっていますが、メソッドを抜ける前にちゃんと hoge.txt がクローズされるようになりました。