【Excel VBA入門 第19回】エラーを起こさない工夫・エラー処理編のまとめ

スポンサーリンク
Excel VBA

イントロダクション

第16回から続けてきたエラー処理編も、今回が最終回である。これまでの3回では、エラーが「起きた後」にどう対処するかを学んできた。

  • 第16回:On Error GoTo で捕まえ、Err オブジェクトで原因を知る
  • 第17回:On Error Resume Next で無視し、Resume でやり直す
  • 第18回:Err.Raise で伝え、後始末を1か所にまとめる

今回はその一歩手前、「そもそもエラーを起こさない」ための事前チェックを取り上げる。エラー処理と事前チェックは対になる考え方であり、両方を使い分けられるようになると、マクロがぐっと安定する。

事前チェックとエラー処理、どちらを使うか

まず、この2つの違いを整理しておこう。

  • 事前チェック:処理を実行する前に、条件をIfで確認し、問題があれば手前で止める
  • エラー処理:処理を実行してみて、失敗したらOn Errorで対処する

「入力された値が数値かどうか」のように、チェックする方法が用意されている場合は、事前チェックのほうが分かりやすい。一方、「ファイルを開けるかどうか」のように、実際にやってみないとわからない場合は、エラー処理に頼ることになる。

IsNumericで数値かどうかを事前に確認する

第16回では、InputBox に文字列を入れるとエラーになり、それをOn Errorで受け止めていた。これを、IsNumeric 関数を使った事前チェックに書き直してみよう。

Sub 割り算の計算_事前チェック版()
    Dim 入力A As String
    Dim 入力B As String

    入力A = InputBox("割られる数を入力してください")
    If Not IsNumeric(入力A) Then
        MsgBox "数値を入力してください。", vbExclamation
        Exit Sub
    End If

    入力B = InputBox("割る数を入力してください")
    If Not IsNumeric(入力B) Then
        MsgBox "数値を入力してください。", vbExclamation
        Exit Sub
    End If

    If CDbl(入力B) = 0 Then
        MsgBox "0で割ることはできません。", vbExclamation
        Exit Sub
    End If

    MsgBox 入力A & " ÷ " & 入力B & " = " & CDbl(入力A) / CDbl(入力B)
End Sub

IsNumeric で文字列かどうかを判定し、= 0 で0かどうかを判定することで、On Error を使わずにエラーを未然に防いでいる。第16回のコードと見比べると、どちらも同じ場面に対応できることがわかるだろう。

事前チェック版のほうが、何を確認しているのかがコードを読むだけでわかるという利点がある。一方で、確認する項目が増えるほどIfが増えてしまうという面もある。

シート存在確認を事前チェックの形で書く

第17回では、On Error Resume Next を使ってシートの存在を確認した。実はこれは、For Each でシート一覧を調べることでも実現できる。

Function シートが存在する2(シート名 As String) As Boolean
    Dim ws As Worksheet

    For Each ws In ThisWorkbook.Worksheets
        If ws.Name = シート名 Then
            シートが存在する2 = True
            Exit Function
        End If
    Next ws

    シートが存在する2 = False
End Function

こちらはOn Errorを一切使わず、シート名を順番に比較しているだけである。
動作は第17回の版と同じだが、仕組みがわかりやすいという良さがある。

シートの数が多い場合などは、実際の処理内容によって速度差が生じることもある。どちらが優れているというより、仕組みを理解しやすい書き方と、実務でよく使われる書き方の両方を知っておくことに意味がある。

事前チェックでは防ぎきれない場面

事前チェックは万能ではない。たとえば、次のようにファイルの存在をDir関数で確認してから開く場合を考えてみよう。

Sub ブックを開く_事前チェック版()
    Dim パス As String
    パス = "C:\test\データ.xlsx"

    If Dir(パス) = "" Then
        MsgBox "ファイルが見つかりません。", vbExclamation
        Exit Sub
    End If

    Dim wb As Workbook
    Set wb = Workbooks.Open(パス)
    MsgBox wb.Name & " を開きました。"
End Sub

Dirでファイルの存在を確認しても、その直後に他の人がファイルを削除したり、ファイルが壊れていたりすれば、Workbooks.Openは失敗しうる。事前チェックをすり抜けてくる失敗に備えて、事前チェックとエラー処理を組み合わせるのが、実務では現実的な選択になる。

Sub ブックを開く_組み合わせ版()
    Dim パス As String
    パス = "C:\test\データ.xlsx"

    If Dir(パス) = "" Then
        MsgBox "ファイルが見つかりません。", vbExclamation
        Exit Sub
    End If

    On Error GoTo エラー処理
    Dim wb As Workbook
    Set wb = Workbooks.Open(パス)
    MsgBox wb.Name & " を開きました。"
    Exit Sub

エラー処理:
    MsgBox "ファイルを開けませんでした。" & vbCrLf & Err.Description, vbExclamation
End Sub

事前チェックで防げる失敗は手前で防ぎ、それでも起こりうる失敗はエラー処理で受け止める。
この二段構えが、安定したマクロの基本形である。

エラー処理編のまとめ

第16回から今回まで、4回にわたってエラー処理を学んできた。最後に、全体を振り返っておこう。

回テーマ主な内容
第16回基本On Error GoTo、Err.Number、Err.Description
第17回無視とやり直しOn Error Resume Next、On Error GoTo 0、Err.Clear、Resume
第18回伝達と後始末Err.Raise、Resume ラベル名による後始末の一本化
第19回事前チェックIsNumeric、Dir、事前チェックとエラー処理の組み合わせ

エラー処理は、覚えることが多く感じられるかもしれない。しかし考え方はシンプルで、「防げる失敗は事前チェックで防ぎ、防げない失敗はエラー処理で受け止め、後始末を忘れない」という一言に集約される。

これで、第12回から続いた「Function・引数・エラー処理」編がひと区切りとなる。
次回からは新しいテーマで、このシリーズを続けていく予定である。お楽しみに。

コメント

タイトルとURLをコピーしました