連載

プロフェッショナルVB.NETプログラミング

第16回 例外処理を極める

(株)ピーデー
川俣 晶
2002/09/07

Page1 Page2 Page3

Finally文の確実性

 Tryブロック内で使用するFinally文についてはすでに説明した。では、これはどの程度確実に動作するものなのだろうか。果たして、無条件に頼ってよいものなのだろうか? それを確認するために以下のようなサンプル・プログラムを記述してみた。これはさまざまなケースで、Finally文を使用してみたものだ。

  1: Private Sub test1()
  2:   Try
  3:     Exit Sub
  4:   Finally
  5:     Trace.WriteLine("Finally called in test1")
  6:   End Try
  7: End Sub
  8:
  9: Private Sub test2()
 10:   Do
 11:     Try
 12:       Exit Do
 13:     Finally
 14:       Trace.WriteLine("Finally called in test2")
 15:     End Try
 16:   Loop
 17: End Sub
 18:
 19: Private Sub test3()
 20:   Try
 21:     Do
 22:       Exit Do
 23:     Loop
 24:   Finally
 25:     Trace.WriteLine("Finally called in test3")
 26:   End Try
 27: End Sub
 28:
 29: Private Sub test4()
 30:   Try
 31:     Dim i As Integer
 32:     For i = 0 To 9
 33:       If i = 5 Then
 34:         Try
 35:           Exit Sub
 36:         Finally
 37:           Trace.WriteLine("Finally called in test4A")
 38:         End Try
 39:       End If
 40:     Next
 41:   Finally
 42:     Trace.WriteLine("Finally called in test4B")
 43:   End Try
 44: End Sub
 45:
 46: Private Sub test5()
 47:   Try
 48:     While True
 49:       Do
 50:         Do
 51:           Exit While
 52:         Loop
 53:       Loop
 54:     End While
 55:   Finally
 56:     Trace.WriteLine("Finally called in test5")
 57:   End Try
 58: End Sub
 59:
 60: Private Sub test6()
 61:   Try
 62:     Do
 63:       Do
 64:         Do
 65:           Throw New Exception("Sample")
 66:         Loop
 67:       Loop
 68:     Loop
 69:   Catch ex As Exception
 70:     Trace.WriteLine("Catch called in test6")
 71:   Finally
 72:     Trace.WriteLine("Finally called in test6")
 73:   End Try
 74: End Sub
 75:
 76: Private Sub test7()
 77:   Try
 78:     '何もない
 79:   Finally
 80:     Trace.WriteLine("Finally called in test7")
 81:   End Try
 82: End Sub
 83:
 84: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 85:   test1()
 86:   test2()
 87:   test3()
 88:   test4()
 89:   test5()
 90:   test6()
 91:   test7()
 92: End Sub
さまざまなケースでのFinally文の動作を検証するVB.NETのサンプル・プログラム7

 これを実行すると以下のようになる。

 1: Finally called in test1
 2: Finally called in test2
 3: Finally called in test3
 4: Finally called in test4A
 5: Finally called in test4B
 6: Finally called in test5
 7: Catch called in test6
 8: Finally called in test6
 9: Finally called in test7
サンプル・プログラム7の実行結果

 1〜7行目のコードは、いきなりメソッドから抜け出した場合である。実行結果を見ると5行目が実行されることが分かると思う。

 9〜17行目は繰り返しの途中から脱出する場合である。実行結果を見ると14行目が実行されることが分かると思う。

 19〜27行目は繰り返しの途中から脱出だが、Tryブロックがループの外側にある点が異なる。実行結果を見ると25行目が実行されることが分かると思う。脱出する個所がTryブロックの中でありさえすれば、Tryブロックを記述する場所に関係なく、Finally文が実行される。

 29〜44行目はTryブロックが2重にネストしていて、どちらにもFinally文が存在する場合である。実行結果を見ると37行目も42行目も、両方とも実行されることが分かると思う。複数のTryブロックがネストして複数のFinally文が存在する場合、それらはすべて実行される。そのため、上位あるいは下位のTryブロックにすでにFinally文が存在するかどうか、気にする必要はない。書けば実行される。

 46〜58行目は繰り返しがネストした途中から脱出する場合である。実行結果を見ると56行目が実行されることが分かると思う。ネストの深さはFinally文の実行とは関係ない。

 60〜74行目は繰り返しの途中から例外が発生した場合である。実行結果を見ると70行目と72行目が実行されることが分かると思う。深いネスト状態から例外が起きても、Finally文は確実に実行される。

 76〜82行目は何も問題なくTryブロックの実行を終える場合である。実行結果を見ると80行目が実行されることが分かると思う。途中脱出や例外の発生がなくても、Finally文はTryブロックから抜ける際に実行される。

深い階層からの例外とFinally文

 Finally文の動作を確認するために、もう1つサンプル・プログラムを記述してみた。このサンプル・プログラムは、メソッド呼び出しが何重にも行っていて、その内部で例外を発生させている。

  1: Private Sub test1()
  2:   Dim i As Integer, j As Integer
  3:   Trace.WriteLine(i \ j)
  4: End Sub
  5:
  6: Private Sub test2()
  7:   Try
  8:     test1()
  9:   Finally
 10:     Trace.WriteLine("Finally called in test2")
 11:   End Try
 12: End Sub
 13:
 14: Private Sub test3()
 15:   Try
 16:     test2()
 17:   Finally
 18:     Trace.WriteLine("Finally called in test3")
 19:   End Try
 20: End Sub
 21:
 22: Private Sub test4()
 23:   Try
 24:     test3()
 25:   Finally
 26:     Trace.WriteLine("Finally called in test4")
 27:   End Try
 28: End Sub
 29:
 30: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 31:   Try
 32:     test4()
 33:   Catch ex As DivideByZeroException
 34:     Trace.WriteLine("ゼロ除算が発生しました。")
 35:   End Try
 36: End Sub
深い階層で発生した例外に対するFinally文の動作を検証するVB.NETのサンプル・プログラム8

 これを実行すると以下のようになる。

 1: Finally called in test2
 2: Finally called in test3
 3: Finally called in test4
 4: ゼロ除算が発生しました。
サンプル・プログラム8の実行結果

 このプログラムは、test1メソッドで例外が発生し、Form1_Loadメソッドでその例外をキャッチしている。そこでポイントになるのは、その中間に位置するtest2〜4メソッドに含まれるFinally文である。例外をキャッチするTryブロックは、Form1_Loadメソッド内にあるが、それではこの例外をキャッチしないTryブロックを持つtest2〜4メソッドに含まれるFinally文はどうなるだろうか。

 結果を見て分かるとおり、すべてのFinally文に続くコードが実行されている。Finally文は、そのTryブロックでキャッチするか否かを問わず、すべて有効である。

次回予告

 次回は名前空間に関する解説を予定している。End of Article


 INDEX
  連載 プロフェッショナルVB.NETプログラミング
  第16回 例外処理を極める
    1.例外の自作
    2.InnerExceptionについて
  3.Finally文の確実性
 
「プロフェッショナルVB.NETプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間