
Java超|finallyで安全な後処理を行う
どんな展開になっても、最後の後片付けは finally が守ってくれる。Javaの finally は、例外が起きても起きなくても実行したい処理を書くための大切な締めくくり役です。
プログラムでは、処理がうまく進むこともあれば、途中で例外が起きることもあります。
try-catch を使えば、例外が起きたときに catch で受け止めて、分かりやすいメッセージを表示したり、別の処理へ進めたりできます。
しかし、実際のプログラムでは、それだけでは足りない場面があります。
たとえば、次のような処理です。
| 最後に必要な処理 | なぜ必要か |
|---|---|
| ファイルを閉じる | 開いたままだと次の処理に影響することがある |
| ネットワーク接続を終了する | 接続しっぱなしを防ぐため |
| データベース接続を閉じる | 資源を使い続けないようにするため |
| 使用中の装置や資源を解放する | 無駄な利用や不整合を防ぐため |
| 最後の確認メッセージを出す | 処理の終わりを分かりやすくするため |
このような処理は、例外が起きた場合だけ必要になるわけではありません。
例外が起きても、起きなくても、最後に必ず行いたい処理です。
そこで使うのが finally です。
finally は、try-catch と組み合わせて使い、最後に必ず実行したい処理を書くためのブロックです。
例外が起きた場合でも、起きなかった場合でも、finally の中の処理は実行されます。
ドラゴンボール風にたとえると、危険な修行や任務のあとに、必ず重力室を停止し、スカウターの記録を閉じ、カプセル装置を安全状態に戻すようなものです。
悟空の修行が無事に終わっても、途中でトラブルが起きても、最後には重力装置を止める必要があります。
ベジータが修行中に異常値を出しても、装置をつけっぱなしにしておくわけにはいきません。
Javaの finally も同じです。
try で処理を試す。
例外が起きたら catch で受け止める。
そして、どんな流れになっても finally で最後の後片付けをする。
この考え方を身につけると、より安全で丁寧なプログラムを書けるようになります。
finallyとは何か
finally は、try-catch と組み合わせて使うブロックです。
役割はとてもシンプルです。
最後に必ず実行したい処理を書く場所です。
基本の形は次のようになります。
try {
例外が起きるかもしれない処理
}
catch(例外のクラス 変数名) {
例外が起きたときの処理
}
finally {
最後に必ず行う処理
}try、catch、finally の役割を整理すると、次のようになります。
| ブロック | 役割 | ドラゴンボール風のイメージ |
|---|---|---|
| try | 例外が起きるかもしれない処理を書く | 危険を含む修行や任務を実行する |
| catch | 例外が起きたときに受け止める | ピッコロやブルマの支援がトラブルを受け止める |
| finally | 最後に必ず実行する処理を書く | 重力室の停止、記録装置の終了、装備の片づけを行う |
finally は、例外処理そのものを書く場所というより、処理の締めくくりを書く場所です。
たとえば、戦士本部の重力室で、悟空たちの戦闘力を記録する処理を考えます。
修行記録が成功しても、途中で名簿の範囲外を指定してしまっても、最後には記録装置を止める必要があります。
この「どんな結果でも最後に行う処理」を書くのが finally です。
try-catchだけでは足りない場面
try-catch を使えば、例外が起きたときの対応はできます。
しかし、後片付け処理を書く場所を間違えると、必要な処理が実行されない場合があります。
たとえば、後片付け処理を try の最後に書いた場合です。
try {
危険な処理
後片付け処理
}
catch(例外のクラス e) {
例外時の処理
}この場合、危険な処理で例外が起きると、try の残りは実行されません。
つまり、try の最後に書いた後片付け処理まで到達できないことがあります。
一方、後片付け処理を catch の中だけに書いた場合は、例外が起きなかったときに実行されません。
try {
危険な処理
}
catch(例外のクラス e) {
例外時の処理
後片付け処理
}これでは、正常に処理が終わったときに後片付けが行われません。
そこで finally を使います。
| 後片付けを書く場所 | 問題点 |
|---|---|
| try の最後 | try の途中で例外が起きると実行されないことがある |
| catch の中だけ | 例外が起きなかった場合に実行されない |
| finally | 例外の有無に関係なく実行される |
ドラゴンボール風に言えば、修行が成功したときだけ重力室を停止する、またはトラブルが起きたときだけ停止する、というのは不十分です。
修行が成功しても、失敗しても、最後に重力室や記録装置を安全に止める必要があります。
そのための場所が finally です。
finallyの基本の流れ
finally は、try-catch の最後に置かれます。
流れは次のようになります。
| 状況 | try | catch | finally |
|---|---|---|---|
| 例外が起きない | 最後まで実行される | 実行されない | 実行される |
| 例外が起きて catch が一致する | 途中で中断される | 実行される | 実行される |
つまり finally は、正常終了でも例外発生でも実行されます。
ここが finally の一番大切なポイントです。
try が最後まで進んでも finally は動きます。
try の途中で例外が起き、catch に移動しても finally は動きます。
ドラゴンボール風に言えば、悟空の修行が成功しても、ベジータの重力修行中に警報が鳴っても、最後には重力室の安全装置を切る、ということです。
図:finallyは最後に必ず実行される

この図が示していること
この図は、例外が起きない場合と、例外が起きる場合の両方で finally が実行されることを表しています。
例外が起きない場合は、try の処理が最後まで進み、その後 finally が実行されます。
例外が起きる場合は、try の途中で処理が中断され、catch に移動します。
その後、finally が実行されます。
| 流れ | finally の動き |
|---|---|
| try が正常に終わる | finally が実行される |
| try の途中で例外が起きる | catch のあとに finally が実行される |
この図から分かることは、finally が「正常時だけ」「例外時だけ」の処理ではなく、どちらの場合でも実行される締めくくりの処理だということです。
finally の動きを確認する
ここでは、配列の範囲外アクセスを使って、finally の動きを確認します。
5人分の戦闘力を記録できる配列を用意します。
しかし、10番目に値を書き込もうとします。
配列の範囲をこえるため、ArrayIndexOutOfBoundsException が発生します。
その例外を catch で受け止めたあと、finally が実行される流れを見ていきます。
ファイル名:Sample3.java
class Sample3
{
public static void main(String[] args)
{
try {
int[] power;
power = new int[5];
System.out.println("戦士本部の修行名簿の10番目に戦闘力を記録します。");
power[10] = 9000;
System.out.println("10番目への記録が完了しました。");
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("記録できる範囲をこえています。");
}
finally {
System.out.println("重力修行室の記録装置を必ず停止します。");
}
System.out.println("修行データの確認を終えました。");
}
}プログラムの全体像
このプログラムには、try、catch、finally の3つがあります。
try {
int[] power;
power = new int[5];
System.out.println("戦士本部の修行名簿の10番目に戦闘力を記録します。");
power[10] = 9000;
System.out.println("10番目への記録が完了しました。");
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("記録できる範囲をこえています。");
}
finally {
System.out.println("重力修行室の記録装置を必ず停止します。");
}それぞれの役割は次の通りです。
| 部分 | 内容 |
|---|---|
| try | 配列を作り、10番目に戦闘力を記録しようとする |
| catch | 配列の範囲外アクセスを受け止める |
| finally | 重力修行室の記録装置を必ず停止する |
| try-catch-finally の後ろ | 修行データの確認終了を表示する |
ドラゴンボール風に言えば、try は修行名簿への記録作業です。
catch は名簿の範囲外を指定したときの支援役の対応です。
finally は、どんな結果でも最後に記録装置を止める後片付けです。
配列の範囲外アクセスが起きる
このプログラムでは、次のように配列を作成しています。
int[] power;
power = new int[5];new int[5] によって、5個分の int 型データを入れる場所が作られます。
Javaの配列の添字は 0 から始まります。
| 配列の要素数 | 使える添字 |
|---|---|
| 5 | 0, 1, 2, 3, 4 |
つまり、power 配列で使えるのは power[0] から power[4] までです。
しかし、次の行では power[10] に値を入れようとしています。
power[10] = 9000;これは範囲外アクセスです。
そのため、ArrayIndexOutOfBoundsException が発生します。
| 処理 | 結果 |
|---|---|
| power[0] から power[4] | 使える |
| power[10] | 範囲外なので例外が発生する |
例外が発生すると、try の後続処理は中断されます。
そのため、次の文は実行されません。
System.out.println("10番目への記録が完了しました。");記録に失敗しているため、成功メッセージには進まないわけです。
catchで例外を受け止める
配列の範囲外アクセスによって ArrayIndexOutOfBoundsException が発生すると、対応する catch が動きます。
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("記録できる範囲をこえています。");
}catch の丸かっこの中には、受け止めたい例外の種類を書きます。
| 部分 | 意味 |
|---|---|
| ArrayIndexOutOfBoundsException | 配列の範囲外アクセスを表す例外 |
| e | 受け取った例外を入れる変数名 |
今回発生する例外は ArrayIndexOutOfBoundsException です。
catch に書いている種類と一致するため、catch の中の処理が実行されます。
ドラゴンボール風に言えば、修行名簿の存在しない欄に記録しようとした警告を、ブルマの解析システムが受け止めて、
「記録できる範囲をこえています。」
と知らせてくれるイメージです。
finallyで最後の処理を実行する
catch の処理が終わると、finally が実行されます。
finally {
System.out.println("重力修行室の記録装置を必ず停止します。");
}この finally は、例外が起きたかどうかに関係なく実行されます。
今回のプログラムでは、例外が起きています。
それでも finally は実行されます。
| 状況 | finally |
|---|---|
| 例外が起きる | 実行される |
| 例外が起きない | 実行される |
このサンプルでは、finally の中で「重力修行室の記録装置を必ず停止します。」と表示しています。
これは学習用の分かりやすい例ですが、実際のプログラムでは、ファイルを閉じる、接続を終了する、資源を解放する、といった処理を書く場面があります。
ドラゴンボール風にたとえると、修行が成功しても失敗しても、最後に重力装置を止め、記録装置を閉じ、カプセル道具を保管棚へ戻すような処理です。
実行結果
このプログラムを実行すると、次のようになります。
戦士本部の修行名簿の10番目に戦闘力を記録します。
記録できる範囲をこえています。
重力修行室の記録装置を必ず停止します。
修行データの確認を終えました。この流れを表にすると、次のようになります。
| 表示 | どこで実行されたか |
|---|---|
| 戦士本部の修行名簿の10番目に戦闘力を記録します。 | try |
| 記録できる範囲をこえています。 | catch |
| 重力修行室の記録装置を必ず停止します。 | finally |
| 修行データの確認を終えました。 | try-catch-finally の後ろ |
ここで注目したいのは、finally のメッセージが表示されていることです。
try の中で例外が起きています。
それでも finally の処理は飛ばされません。
さらに、catch と finally の処理が終わったあと、try-catch-finally の後ろにある処理も実行されています。
Sample3.javaの処理の流れ
このプログラムの流れを順番に整理すると、次のようになります。
| 順番 | 処理 | 実際の動き |
|---|---|---|
| 1 | try に入る | 修行名簿への記録処理を始める |
| 2 | 配列を作る | power = new int[5]; が実行される |
| 3 | 登録開始メッセージを表示 | 10番目に戦闘力を記録すると表示 |
| 4 | power[10] に代入しようとする | 範囲外なので例外が発生 |
| 5 | try の残りを中断 | 記録完了メッセージは実行されない |
| 6 | catch に移動 | 範囲外アクセスを受け止める |
| 7 | catch の処理を実行 | 記録できる範囲をこえています。 |
| 8 | finally を実行 | 重力修行室の記録装置を必ず停止します。 |
| 9 | 後続処理へ進む | 修行データの確認を終えました。 |
try-catch-finally の流れで大切なのは、finally が catch のあとに実行されていることです。
例外が起きた場合は、try から catch へ移動し、その後 finally へ進みます。
図:Sample3.javaでfinallyが動く流れ

この図が示していること
この図は、Sample3.java の中で例外が発生し、catch と finally が順番に実行される流れを表しています。
try の中で power[10] = 9000; が実行されると、配列の範囲外アクセスが起きます。
そのため、try の中にある記録完了メッセージは実行されません。
その後、catch が例外を受け止め、finally で記録装置の停止処理を行います。
| 図のポイント | 内容 |
|---|---|
| power[10] | 例外が発生する場所 |
| 記録完了メッセージ | 例外発生後なので実行されない |
| catch | 範囲外アクセスを受け止める |
| finally | 最後に必ず実行される |
| 後続処理 | finally のあとに進む |
この図から分かることは、finally は try の最後にある処理ではなく、try-catch の流れの最後に用意された特別な後処理ブロックだということです。
finallyはどんなときに実行されるのか
finally は、例外が起きた場合だけに実行されるものではありません。
例外が起きても、起きなくても実行されます。
もう一度、流れを整理します。
| 状況 | try | catch | finally |
|---|---|---|---|
| 例外が起きない | 最後まで実行される | 実行されない | 実行される |
| 例外が起きて catch が一致する | 途中で中断される | 実行される | 実行される |
この性質があるため、finally には後片付け処理を書くのに向いています。
ドラゴンボール風にたとえると、修行が成功しても、途中で名簿の記録ミスが起きても、最後には重力修行室の記録装置を停止するということです。
| 任務の結果 | 最後に行うこと |
|---|---|
| 修行記録が成功した | 記録装置を停止する |
| 範囲外アクセスで失敗した | 記録装置を停止する |
| catch で対応した | 記録装置を停止する |
finally は、処理の成功や失敗に左右されず、最後に必要な作業を実行するための場所です。
try・catch・finallyの役割の違い
try、catch、finally は、並んで書くことが多いため、役割を混同しやすいです。
しかし、それぞれの担当ははっきり違います。
| ブロック | 何を書くか | 目的 |
|---|---|---|
| try | 例外が起きるかもしれない処理 | まず処理を試す |
| catch | 例外が起きたときの対応 | 問題を受け止める |
| finally | 最後に必ず行う処理 | 後片付けや終了処理を行う |
try は、通常の処理を進める場所です。
catch は、例外が起きたときの対応を書く場所です。
finally は、成功したか失敗したかに関係なく、最後に行う処理を書く場所です。
ドラゴンボール風に整理すると、次のようになります。
| Java | ドラゴンボール風の役割 |
|---|---|
| try | 修行名簿に戦闘力を記録する処理 |
| catch | 範囲外の記録ミスを受け止める支援役 |
| finally | 最後に重力装置や記録装置を停止する記録係 |
このように役割を分けると、try-catch-finally の流れがかなり分かりやすくなります。
なぜfinallyが必要なのか
finally が必要になる理由は、重要な後処理を実行し忘れないためです。
たとえば、ファイルを開いて作業するプログラムを考えます。
ファイルを開いたあと、処理が正常に終われば、最後にファイルを閉じる必要があります。
しかし、途中で例外が起きた場合でも、ファイルは閉じなければなりません。
もしファイルを閉じる処理を try の最後にだけ書いていたら、try の途中で例外が起きたときに実行されない可能性があります。
もし catch の中にだけ書いていたら、例外が起きなかった場合に実行されません。
だから finally が必要です。
| 書き方 | 問題点 |
|---|---|
| try の最後に後処理を書く | try の途中で例外が起きると実行されないことがある |
| catch の中だけに後処理を書く | 例外が起きない場合に実行されない |
| finally に後処理を書く | 例外の有無に関係なく実行される |
プログラムでは、成功したときの流れだけでなく、失敗したときも後始末できることが重要です。
finally は、そのための仕組みです。
finallyに書くべき処理
finally に書くのは、最後に必ず行う必要がある処理です。
代表的なものは次の通りです。
| 処理の種類 | finally に書く理由 |
|---|---|
| ファイルを閉じる | ファイルを開いたままにしないため |
| 通信を終了する | 接続しっぱなしを防ぐため |
| データベース接続を閉じる | 資源を解放するため |
| 装置や資源を解放する | 使い終わったものを戻すため |
| 最後の確認メッセージを出す | 処理の終わりを明確にするため |
今回のサンプルでは、学習用に次のメッセージを finally に書いています。
System.out.println("重力修行室の記録装置を必ず停止します。");
これは、実務でいう「使い終わった資源を閉じる」「最後の後片付けを行う」という処理のイメージです。
ドラゴンボール風にたとえると、重力修行室の記録装置を止める、通信装置を切る、カプセル道具を保管棚へ戻すような処理です。
図:finallyに書く後処理のイメージ

この図が示していること
この図は、finally に書くべき処理のイメージを表しています。
finally は、例外対応そのものを書く場所ではなく、最後に必ず行いたい後処理を書く場所です。
| finally に向いている処理 | 内容 |
|---|---|
| ファイルを閉じる | 開いた巻物を閉じる |
| 通信を終了する | 通信装置の接続を切る |
| 接続を閉じる | 使い終わった端末を停止する |
| 装置を停止する | 重力修行室の記録装置を止める |
この図から分かることは、finally がプログラムの後始末を安全に行うための場所だということです。
catchがあってもfinallyが大切な理由
catch があれば、例外が起きたときに対応できます。
しかし、catch は「例外が起きたとき」に動くブロックです。
一方、finally は「最後に必ず」動くブロックです。
この違いが重要です。
| ブロック | 実行される条件 |
|---|---|
| catch | 対応する例外が起きたとき |
| finally | 例外の有無に関係なく実行される |
もし後片付けを catch にだけ書いてしまうと、例外が起きなかった場合には実行されません。
だから、後片付けのように必ず必要な処理は finally に書くのが自然です。
ドラゴンボール風にたとえると、ピッコロの支援はトラブルが起きたときに対応します。
しかし、ブルマの設備停止チェックは、トラブルが起きても起きなくても必要です。
catch はトラブル対応。
finally は最後の締め作業。
このように分けて考えると、役割がすっきりします。
catchが見つからない場合とfinally
finally は、catch がある場合だけ大切なのではありません。
例外処理では、現在のメソッド内に対応する catch が見つからない場合、呼び出し元へ例外が伝わっていくことがあります。
そのような場合でも、そのメソッドを離れる前に必ず行いたい処理があります。
たとえば、ドラゴンボール風に言えば、任務の最終判断は戦士本部へ引き継ぐとしても、その場の重力修行室の装置だけは止めてから離れたい、という場面です。
finally は、そのような「この場所を離れる前に必ず行う処理」を書くためにも役立ちます。
| 状況 | finally の意味 |
|---|---|
| catch で例外を受け止める | catch のあとに後処理を行う |
| catch が見つからず呼び出し元へ進む | その前に必要な後処理を行う |
| 例外が起きない | 通常処理のあとに後処理を行う |
finally は、処理の流れがどう進んでも、必要な締めくくりを行うための重要なしくみです。
finallyで押さえておきたいポイント
finally を学ぶときは、次の点を押さえておくと理解しやすいです。
| ポイント | 内容 |
|---|---|
| finally の役割 | 最後に必ず行う処理を書く |
| 実行される条件 | 例外が起きても起きなくても実行される |
| try の中で例外が起きた場合 | catch のあとに finally が実行される |
| try が正常に終わった場合 | catch は動かず finally が実行される |
| 書く内容 | 後片付け、終了処理、接続解除、資源解放など |
| 使う意味 | 重要な処理の実行漏れを防ぐ |
finally は派手な機能ではありません。
しかし、実際のプログラムではとても大切です。
プログラムでは、成功したときだけでなく、失敗したときにもきちんと後始末できることが重要です。
ドラゴンボール風に言えば、強い技を出すことだけが任務ではありません。
修行のあとに重力装置を止め、記録を閉じ、修行室を整えるところまでが大切です。
Javaの finally も同じです。
例外が起きても、起きなくても、最後に必要な処理をきちんと実行する。
そのための締めくくり役が finally です。
