そもそも Try-Catch-Finally って何者?
「例外処理」と聞くと、ちょっと身構える方も多いかもしれません。
でも実際は「やばそうな処理を安全なクッションでくるむ」――ただそれだけです。
- Try:まずやってみるブロックです。ここでワクワクしながら処理を試します。
- Catch:もし転んだら(=例外が起きたら)ここで受け止めます。
- Finally:転んでも転ばなくても、最後に後片づけをします。床を雑巾がけするイメージです。
難しい概念に見えますが、ざっくり言うと「チャレンジ → エラー対応 → お片づけ」の三段構えです。
よくある「一般的な説明」にモヤッとする理由
解説サイトを巡ると、
Try で処理を書き〜 Catch でエラーハンドリングし〜 Finally で必ず実行される処理を書きます。
と一本調子で説明されることが多いです。
でも実際にコードを書くとき、「どこに何を書く?」 があいまいだと手が止まります。
- Catch は何個でも良いの?
- Finally って毎回書くべき?
- 「とりあえず Exception で全部捕まえればいいや」はアリ?
そんな曖昧さが、初心者だけでなく中堅開発者の足も意外と引っ張ります。
動作確認環境
下記の環境で動作確認しています。
- .NET9
- Visual Studio 2022
雑なサンプルですが、ソースコードはこちら
もう少し寄り添ってみる:ポイント別の整理
1. Catch は具体的な型から書く
例外にはたとえば DivideByZeroException
や IOException
など、専門職のように多くの種類があります。
まずは「起こりそうな特定の例外」から Catch しましょう。
最後に力技(Exception
)を置けば、万が一の拾い漏れを防げます。
Try Dim a = 10 Dim b = 0 Dim answer = a \ b ' ゼロ除算の例 Catch ex As DivideByZeroException Console.WriteLine("ゼロで割っちゃいました: " & ex.Message) Catch ex As Exception Console.WriteLine("想定外の例外です: " & ex.Message) End Try
2. Finally は「絶対やるべき後始末」があるときだけ
毎回書けと言われがちですが、必ずしも必須ではありません。
たとえばファイルを開いたら閉じる、DB 接続を開いたら閉じる。
そういった「リソース解放」が必要なときにだけ使うとスッキリします。
3. Try の外で初期化する勇気
以下のように、リソース変数は Try の外で宣言しておくと Finally で扱いやすいです。
Dim sr As StreamReader = Nothing Try sr = New StreamReader("sample.txt") Console.WriteLine(sr.ReadToEnd()) Catch ex As IOException Console.WriteLine("ファイル操作でエラー: " & ex.Message) Finally If sr IsNot Nothing Then sr.Dispose() End Try
「Nothing チェックが面倒だな」と感じる方は Using
ステートメントも検討してください。
これも立派なクッション材です。
例外処理を巡る “あるある” な葛藤
- 「全部 Exception で拾えばラクなのでは?」問題
→ たしかにコンパイルは通ります。でもエラー原因の切り分けが難しくなり、運用時に首を絞めがちです。 - 「Finally でログ書けばいいや!」問題
→ Finally は必ず通るので便利ですが、正常処理も異常処理も区別せずログが出ます。
結果、ログが洪水のようになって後でつらい思いをします。 - 「Try のネスト地獄」問題
→ ひたすら Try…Catch…Finally… が深くなると読めたものではありません。
メソッドを細かく分けてネストを浅く保つ、といったリファクタリングが必要です。
とはいえ「堅苦しすぎる」のも考えもの
正直、学習段階で「究極の美しい例外処理」を追い求めると、コードが書けなくなります。
- まずは動くものを作り、
- ログで状況を確認し、
- 徐々に細かい Catch を増やす
この三ステップで肩の力を抜きつつ改善していけば十分です。
具体例で流れをつかむ
「座学は分かったけど、実務っぽいサンプルが欲しい!」
という声が聞こえた気がするので、コンソールアプリを例に一連の流れを載せます。
Module Program Sub Main() Console.WriteLine("割り算サービスを開始します") Console.Write("割られる数を入力してください: ") Dim dividend = Integer.Parse(Console.ReadLine()) Console.Write("割る数を入力してください: ") Dim divisor = Integer.Parse(Console.ReadLine()) Try Dim result = SafeDivide(dividend, divisor) Console.WriteLine($"結果は {result} です") Catch ex As DivideByZeroException Console.WriteLine("おっと! 0 では割れません。") Catch ex As FormatException Console.WriteLine("数字をちゃんと入れてください。") Catch ex As Exception Console.WriteLine("想定外のエラーが起きました: " & ex.Message) Finally Console.WriteLine("割り算サービスを終了します") End Try End Sub Private Function SafeDivide(a As Integer, b As Integer) As Double Return a \ b End Function End Module
- FormatException:数値入力ミス用
- DivideByZeroException:ゼロ除算用
- Exception:保険的まとめ取り
これだけで、入力ミスやゼロ除算でもアプリが落ちず、ユーザーに優しい挙動になります。
Try-Catch-Finally をもっと使いこなす Tips
- 複数の Catch を書く順番
具体的な派生型 → 汎用的な親クラス の順に並べます。
逆にすると前の段階で全部拾われ、下の Catch が死文化します。 - 再スロー(Throw)の活用
エラーログを残した後にThrow
だけ書くと、元の例外を上位に投げ直せます。
ログ取りつつ、呼び出し元に判断を委ねられるので便利です。 - Using との併用
Using でリソース解放を自動化しつつ、Try-Catch を外側に書くと読みやすさが向上します。
Try Using conn As New SqlConnection(connStr) conn.Open() ' DB 処理…… End Using Catch ex As SqlException ' ここでだけ DB 例外を扱う End Try
よくある FAQ
疑問 | 考え方 |
---|---|
Finally を書かずに Using だけで良い? | 片付け対象がリソースだけならそれで十分です。 |
Catch で Exception だけ書くのはダメ? | プロトタイプなら OK ですが、本番では原因究明が困難になります。 |
関数の中で Try を複数書くべき? | 1 関数 1 主旨が原則です。気づけばネストが深いなら分割を検討しましょう。 |
というわけで、まとめです
- Try-Catch-Finally は「チャレンジ → エラー対応 → お片づけ」の三段構え
- Catch は 具体例外 → 汎用例外 の順で並べると見通しが良いです。
- Finally は「絶対やる後始末」があるときだけ。不要なら潔く省いて OK です。
- 初めは Exception だけで捕まえても大丈夫。動かしながら改善しましょう。
例外処理は奥が深いですが、最初から完璧を目指すより「安全に壊れにくくする」意識で少しずつ整えていく方が、心もコードも楽になります。
読んでくださったあなたの Try-Catch-Finally ライフがちょっとでも快適になれば嬉しいです。
それでは、良い VB.NET コーディングを!