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文」のように、
プログラムの仕様上、「絶対に処理が来ない場所」があります。
もしもプログラム記述ミスなどの理由で、「絶対に処理が来ない場所」に処理が来た場合、
- プログラム処理を中止する。
- プログラム開発者に、プログラム処理が「この場所に来たこと」を伝える。
以上の事を実行すると、良いです。
なぜなら、プログラムの不具合を見つけて修正する際に、役立つからです。
ソースコードにおいて、以上の事を実行するために、
「絶対に処理が来ない場所」で、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クラスを継承したものです。