アサーション
JavaプログラマGold教科書は名前に反し内容は初心者向けである。とは云いつつ、やはり初心者には難しい箇所もある。その一つがアサーションである。
アサーションとは、プログラマが前提としている条件をチェックし、プログラムの正しい動きを保障するための機能です。
プログラマが「ここは結果がtrueになるだろう」と思ってプログラムを書いても、本当にtrueになるのかどうかは実装してみないとわかりません。アサーション機能を使用すると、trueにならなかった場合は、エラーを表示させることができ、バグの検出に有効です。
assertionは表明の意味である。では表明とは何か。
コトバンクでは次のように定義されている。
表明:[名](スル)自分の考え・決意どを、はっきりあらわし示すこと。「引退を―する」
「自分の考え」が表明ならばプログラムにおいてコメント文こそ表明である。例えば次のメソッドは「100以下の2つの自然数を渡せばその和が戻り値として返却される」というコメント文が表明ということになる。
class Clac {
/**
* 100以下の自然数を2つの引数として渡せばその和が戻り値として返却される
*/
int plus(int p1, int p2){
return p1 + p2;
}
}
大概の表明は事前条件と事後条件で構成される。上の場合、事前条件は「100以下の2つの自然数を渡す」であり、事後条件は「引数の和を戻り値として返す」である。事前条件は呼び出し側が守らなければならない約束事であり、事後条件は呼び出し側が事前条件を守った場合に守らなければならない約束事である。この約束事を呼び出す側と呼び出される側が守れば良いのだが世の中そううまくはいかない。大概の約束は破られる。コメント文による約束は口約束のようなものだ。反故されやすい。
そこでassert文となる。コメント文だけでは心許ないが、assert文を追加すれば約束は守られるに違いない。何故ならassert文との約束を破ればAssertionErrorという怖いお兄さんが怒鳴り込んで来る。無視など到底できない。事前条件をチェックし約束を守らなければならない。だがassert文の導入のメリットはそれだけではない。
class Clac {
/**
* 100以下の自然数を2つの引数として渡せばその和が戻り値として返却される
*/
int plus(int p1, int p2){
assert p1 <= 100 & p1 >= 1 "p1は100以下の自然数でなければなりません";
assert p2 <= 100 & p2 >= 1 "p2は100以下の自然数でなければなりません";
return p1 + p2;
}
}
assert文により事前条件が明確になっていることが分かるだろうか。コメント文は日本語のためあいまいさが残る。そのため呼び出し側は表明を理解できないことがある。だが上の表明は極めて明確である。これはassert文というプログラム言語による表明が追加されたためだ。約束があいまいなら守りたくとも守れない。だが約束が明確であれば守りやすい。
Calc calc= new Clac();
if ( prm1 <=100 & prm1 > 0 & prm2 <=100 & prm2 > 0 ) {
int ret = calc.plus(prm1, prm2);
System.plintln(prm1 + " + " + prm2 + " = " + ret);
}
もしplusメソッドにコメントしかないならこのif文によるチェックは書かれない。だがplusメソッドにはassert文がある。ゆえにif文は必ず書かれる。
これがassert文の威力である。assert文はプログラムを正しい方向に導く。
ところでassert文と似た手法にIllegalArgumentExceptionを使用するやり方がある。
class Clac {
/**
* 100以下の自然数を2つの引数として渡せばその和が戻り値として返却される
*/
int plus(int p1, int p2){
if (p1 > 100 || p1 < 1 ) {
throw new IllegalArgumentException("p1は100以下の自然数でなければなりません");
} else if (p2 > 100 || p2 < 1) {
throw new IllegalArgumentException( "p2は100以下の自然数でなければなりません");
}
return p1 + p2;
}
}
IllegalArgumentExceptionによるバリデーションチェックはassert文による表明とどうちがうのか。これについては改めて説明する。