Javaソースコードにおける、プログラムで実行されない「その他の場合」のif文

Javaソースコードでif文を記述する場合、
「その他の場合」において、エラー情報を出力する方が良いですか?

if文の「その他の場合」においては、エラーを示すログ情報を出力する処理を、記述しましょう。
ログ情報を見ることで、プログラム処理でどういう不具合が起きているか、わかるからです。

if文の「その他の場合」にプログラム処理が来た場合、
プログラムは仕様外の動作をしています。プログラムでエラーが起きています。

if文の「その他の場合」でエラー情報を出力しておくと、プログラムのエラーを修正するのに役立ちます。

Javaソースコードにおける、プログラムで実行されない「その他の場合」のif文

if文で処理を分ける場合、
「その他の場合」において、エラーを示すログ情報を出力しておくと、デバッグ時に役立ちます。

プログラム処理上(プログラム仕様上)実行されない「その他の場合」は、当然実行されないので、プログラム処理を書く必要はありません。

しかし

  • プログラム記述ミス
  • プログラム作成時に予想できない不具合

このような原因によって、本来は実行されない「その他の場合」の部分に、プログラム処理が来てしまうことがあります。

その場合、プログラムが期待通りに動作しない可能性があります。

そのような時、「その他の場合」において、エラーを示すログ情報を出力しておくと、プログラムの不具合に気づきやすい、と思います。

「その他の場合」のif文の例

以下に、「その他の場合」のif文について、ログ情報を出力している例を示します。
プログラムの詳細を理解する必要は、ありません。

public ActionForward perform(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response){
    ...
    MessageBoardForm boardForm = (MessageBoardForm)form;
    String action = boardForm.getAction();
    if (action.equals("forward")){
        int boardID = boardForm.getBoardID();
        ...
    }
    else if (action.equals("back")){
        int boardID = boardForm.getBoardID();
        ...
    }
    else if (action.equals("write")){
        return mapping.findForward("contributionDo");
    }
    else if (action.equals("message")){
        int boardID = boardForm.getBoardID();
        ...
    }
    else{
        //next 休止中.htmlなど、表示する。
        throw new RuntimeException("invalid action=" + action);
    }
    ...
}

if文の「最後のelse部分」が、「その他の場合」の処理です。

次の文で、ログ情報を出力しています。

throw new RuntimeException("invalid action=" + action);

action変数の文字列で処理を分けていますが、どの場合にも当てはまらない時に、ここに来ます。

上記のプログラムでは、プログラム仕様上ありえない場合に、
action変数に「無効な文字列」が設定された場合に、処理が「その他の場合」に来ます。

処理が「その他の場合」に来る時は、プログラム処理上、不具合が起きています。

よってRuntimeExceptionクラスのオブジェクトを作成して、通知します。
実行時に解決できないエラーが発生した、ということで、処理を中断しています。

この自作のエラーは、ログファイルに記録されます。
よって、プログラム処理でどういう不具合が起きているか、わかります。

処理が「その他の場合」に来た時、考えられるプログラムの不具合

処理が「その他の場合」に来た時、プログラムの不具合として、次の事が考えられます。

例:プログラムの記述ミス。

  • action変数に設定する文字列を、間違って記述してしまった。
  • action変数の分岐処理、例えばelse ifのブロックを、書き忘れてしまった。

ここで上記のプログラム例において、以下の場合を考えてみます。

acton変数に、メッセージの削除を示す”delete”文字列が設定されていた。

この時、ユーザーがメッセージの削除命令を実行しても「メッセージが削除されない」という不具合が起きます。

なぜなら、メッセージの削除を示す”delete”に対する「else ifのブロック」が、書かれていないからです。

この時、ログファイルには、
無効な文字列”delete”が、action変数に設定されている
という自作のエラーが出力されます。

このエラー情報により、ソースコードの中から「この不具合の原因部分」を探せます。

※ここまでの記事は、2003年6月当時の記事になります。

Javaプログラミングのif文
Javaプログラミングのif文・イメージ画像

Javaソースコードにおいて、絶対に実行されない文

例えば「その他の場合のif文」のように、
プログラムの仕様上、「絶対に処理が来ない場所」があります。

もしもプログラム記述ミスなどの理由で、「絶対に処理が来ない場所」に処理が来た場合、

  • プログラム処理を中止する。
  • プログラム開発者に、プログラム処理が「この場所に来たこと」を伝える。

以上の事を実行すると、良いです。
なぜなら、プログラムの不具合を見つけて修正する際に、役立つからです。

ソースコードにおいて、以上の事を実行するために、

「絶対に処理が来ない場所」で、catch文で対処しなくて良い例外、
例えばRuntimeExceptionクラスのオブジェクトを作成して、通知します。

public ActionForward perform(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response){
    ...
    MessageBoardForm boardForm = (MessageBoardForm)form;
    String action = boardForm.getAction();
    if (action.equals("forward")){
        int boardID = boardForm.getBoardID();
        ...
    }

中略

    else{
        //プログラム仕様外の処理なので、プログラム処理を中止する
        throw new RuntimeException("invalid action=" + action);
    }
    ...
}

例外を通知すると、ログにエラーに関する情報が記録されます。
よってログを見ることで、プログラムの異常が開発者に伝わる、と思います。

多くの場合で、プログラム処理を中止するという判断で良いです

多くの場合で、RuntimeExceptionクラスのオブジェクトを作成して、通知することは、プログラム処理を中止させることになります。

プログラムの仕様上、「絶対に処理が来ない場所」に処理が来た場合、
プログラムが「異常な動作をする可能性」があります。

なぜなら、プログラム仕様外の処理手順が実行されているからです。

プログラムが異常な処理手順を実行したので、
多くの場合で、プログラム処理を中止するという判断で良いです。

catch文で処理しなくて良い例外クラス

  • Errorクラス
  • RuntimeExceptionクラス

これらは、catch文で処理する必要がない例外クラスです。

これら例外クラスの使い分けについて、次のような意見があります。参考に書きます。

Errorクラス。
実行環境(JavaVMなど)の内部で発生した致命的なエラーを、示します。
プログラムから明示的に通知することはない、という考え方があります。

RuntimeExceptionクラス。
エラー発生の責任がプログラム開発者側にあることを、示します。
例:プログラムの記述ミス

また、RuntimeExceptionクラスに対しては、次のような考え方もあるそうです。

ある不具合が起きたことを例外で示したが、
その例外をキャッチして処理しても、プログラムを頑健にすることに「役立たない感じ」がする。

そんな場合では、プログラムを頑健にするのに役立たないcatch文を、書きたくない。
その意志を示す場合に、RuntimeExceptionクラスを利用する。

このような考え方もあるようです。

RuntimeExceptionクラスは、非チェック例外です

RuntimeExceptionクラスは、Java仮想マシンの通常の処理で通知できる各種例外のスーパークラスです。

RuntimeExceptionクラスとそのサブクラスは、非チェック例外です。

RuntimeExceptionクラスを使用する場合、
その例外が発生した時点でプログラムが中断されます。

そういう事より、例外処理が必要ない場合に限り使用することが推奨されます。

なお、非チェック例外は、メソッドまたはコンストラクタのthrows節で宣言する必要がありません。
なのでその分、コードの可読性が向上します。

一方、Exceptionクラスとそのサブクラスのうちで、RuntimeExceptionクラスのサブクラスでないものは、チェック例外になります。

チェック例外は、メソッドまたはコンストラクタのthrows節で宣言する必要があります。

失敗談:使い分けせずに、Errorクラスを使用してしまった

以前、自作のJavaソースコードで、「絶対に実行されない部分」に処理が来た場合、
Errorクラスを通知していたことがありました。

その当時、「例外クラスの使い分け」を、あまり意識していなかったからです。
Errorの方が、RuntimeExceptionよりも文字数が短かったから、使っていました。

特に深く考えずにErrorクラスを使っていたので、他のプログラマーに対して「わかりにくいソースコード」になっていた、と思います。

※ここまでの記事は、2004年6月当時の記事になります。

Java言語の例外クラスの継承関係

例外クラスの継承関係を図にすると、以下のようになります。

Throwable
├─ Error
│  ├─ OutOfMemoryError
│  ├─ StackOverflowError
│  └─ ...
└─ Exception
   ├─ RuntimeException
   │  ├─ NullPointerException
   │  ├─ ArithmeticException
   │  ├─ ClassCastException
   │  └─ ...
   └─ IOException
      ├─ FileNotFoundException
      ├─ SocketException
      └─ ...

Java言語では、例外クラスはThrowableクラスを継承したErrorクラスとExceptionクラスに分かれます。

Errorクラスは、システムの致命的なエラーを表すものです。
通常は、プログラムでキャッチできません。

Exceptionクラスは、プログラムの実行中に発生するエラーを表すものです。
チェック例外(検査例外)と非チェック例外(非検査例外)に、分けられます。

try-catch文やthrows節が必要、チェック例外

チェック例外は、コンパイル時にチェックされる例外です。
コンパイル時にチェックされるため、チェック例外を通知するメソッドを呼び出す場合は、

  • try-catch文で例外処理を行う。
  • throws節によって、例外を宣言する。

これらのいずれかを行う必要があります。

try-catch文やthrows節は不要、非チェック例外

非チェック例外は、コンパイル時にチェックされない例外です。
コンパイル時にチェックされないため、try-catch文やthrows節は不要です。

非チェック例外は、プログラムの処理手順の不具合や、不正な操作などによって発生します。

非チェック例外は、RuntimeExceptionクラスを継承したものです。

【まとめ記事】へのリンク

【まとめ記事】Javaアプリの品質を保つため、Javaソースコードを書くための工夫

Javaソースコードを正しく書くための、ちょっとした工夫について、ご紹介しています。 変数の寿命を限定する書き方。 肯定的な条件を優先して条件分岐する書き方。 クラス…