【VBA】エラーハンドリングの基本(サブプロシージャからエラーを投げる)
今回はVBAの上級テクニックを紹介します。
サブプロシージャからエラーを投げて、メイン処理を中止させる方法です。

図にするとこのような状況です。
メインプロシージャがサブプロシージャを呼び出ししていたのだが、サブプロシージャの実行中に問題があると判明したときです。
例えば、サブプロシージャでセルの値を読み込んだけれど、数字のはずの値が実は文字列だったなど。
こうしたとき、エラーメッセージを表示して処理を中止させたいです。
しかし、サブプロシージャ上でExit Subとしても、それはサブプロシージャが終了するだけでメインプロシージャの処理は継続してしまいます。
そのため、サブプロシージャにExit Subではない方法を組み込んで、メインプロシージャを終了させる必要があります。
今回説明するのは、こうしたときに使えるテクニックです。
[微妙な方法]サブプロシージャをFunctionにしてBooleanを返す
最初に、エラーハンドリングを使わない微妙な方法を紹介します。
具体的には、サブプロシージャ内で問題が起こったときには、サブプロシージャがBoolean(False)を返す方法です。
Sub MainProcedure()
Dim isSuccess As Boolean
' サブプロシージャを実行
isSuccess = ProcessData(Range("A1"))
' 結果を判定
If isSuccess = False Then
MsgBox "エラー: A1セルの処理に失敗しました。処理を中断します。", vbExclamation, "エラー"
Exit Sub
End If
' 正常時の処理
MsgBox "A1セルの処理が正常に完了しました。", vbInformation, "成功"
End Sub
Function ProcessData(targetCell As Range) As Boolean
' 目的の処理: A1セルの値を2倍にする
If IsNumeric(targetCell.Value) Then
targetCell.Value = targetCell.Value * 2
ProcessData = True ' 成功
Else
ProcessData = False ' 失敗
End If
End Function
サンプルプログラムとしてはこのようになります。
サブプロシージャ(ProcessData)はA1セルが数値でないときは、Falseを返します。
メインプロシージャはTrueなら処理を継続して、FalseならExit Subするようになっています。
処理自体はうまくいくのですが、このコードは読み返すとなかなか分かりづらくなります。
サブプロシージャ(ProcessData)はBooleanを返すのですが、なぜBooleanを返すのか、ぱっと見で分かるでしょうか?
もし、未来の自分が(もしくは他人が)読んだらきっと分からないと思います。
なので、この書き方をするならBooleanの意味をコメントする必要が出てきます。
読みやすいプログラムという観点では、これはあまりいいやり方とは言えません。また、返り値をBooleanにしてしまうと、他の本来返したい値を設定することができません。
そこで、Booleanを使わない、別のテクニックが必要になってくるのです。
エラーハンドリングの基本(サブプロシージャからエラーを投げる)
良い方法はサブプロシージャにエラーを投げさせる、というテクニックです。
Sub MainProcedure()
On Error GoTo ErrorHandler ' エラーハンドラを設定
' サブプロシージャを実行(エラーが発生した場合は自動的にエラーハンドラへ)
ProcessData Range("A1")
' 正常終了時の処理
MsgBox "A1セルの処理が正常に完了しました。", vbInformation, "成功"
Exit Sub
ErrorHandler:
' 独自のエラー 1001 をキャッチ
If Err.Number = 1001 Then
MsgBox "エラー: " & Err.Description, vbExclamation, "処理エラー"
Else
MsgBox "予期しないエラーが発生しました。" & vbCrLf & "エラー番号: " & Err.Number & vbCrLf & "詳細: " & Err.Description, vbCritical, "システムエラー"
End If
Err.Clear
End Sub
Sub ProcessData(targetCell As Range)
' 目的の処理: A1セルの値を2倍にする
If Not IsNumeric(targetCell.Value) Then
Err.Raise 1001, "ProcessData", "A1セルの値が数値ではありません。"
End If
targetCell.Value = targetCell.Value * 2 ' 数値なら処理を実行
End Sub
サンプルプログラムとしてはこのようになります。
先ほどと違い、サブプロシージャ(ProcessData)はA1セルが数値でないときに、エラーを投げます。
If Not IsNumeric(targetCell.Value) Then
Err.Raise 1001, "ProcessData", "A1セルの値が数値ではありません。"
End If
エラーを投げているのは、この部分で、Err.Raiseというのがエラーを投げる専用のメソッドです。
セルの値が数字出ない場合は、エラーを投げます。
そして、メインプロシージャにはOn Error GoToを宣言しているため、エラーが起こるとエラーハンドラ(エラーを処理する部分)に処理が飛ばされます。
この2つの組合せによって、エラー処理を完了させているのです。
イメージとしては、サブプロシージャがピッチャーで、メインプロシージャがキャッチャーみたいな感じですね。
この方法を使えば、Err.Raiseと書かれているのを見るだけでエラー処理が含まれるのだなと判断が付きます。
メインプロシージャも、On Error GoToを見ただけでおおよその処理が想像できます。
ぱっと見では理解できないかもしれませんが、慣れるととても分かりやすい方法なので活用してみて下さい。
サンプルプログラムはきれいに書いたため、一旦これをコピーして、プロシージャ名などだけ差し替えて使ってもらっても大丈夫です。