Javaに関する様々な情報をご紹介します。

4アサーション

Javaに関する様々な情報をご紹介します。

アサーション

ここでは、J2SE 1.4から導入されたアサーションについて解説します。

概要

アサーションとは、バグの少ないプログラム開発を補助する機能です。プログラムコード中に、ある特定の条件をアサーションで記載しておきます。その条件を満たさない場合は、AssertionErrorが返されます。そうすることにより、バグの箇所を早期に発見できるようになります。

----- プログラム処理A -----

//この位置で変数iが0の場合、AssertionErrorが返されます。
assert i != 0 ;

----- プログラム処理B -----

//この位置で変数iが0以上でない場合、AssertionErrorが返されます。
assert i > 0 ;

----- プログラム処理C -----

アサーションとは、バグの少ないプログラム開発を補助する機能です。プログラムコード中に、ある特定の条件をアサーションで記載しておきます。その条件を満たさない場合は、AssertionErrorが返されます。そうすることにより、バグの箇所を早期に発見できるようになります。

基本仕様

アサーションはassertの後にbooleanを返す式1を記載します。trueが返る場合は何もおきませんが、falseが返る場合はAssertionErrorが返されます。
式2を記載した場合は、AssertErrorが返された場合に、詳細メッセージとして式2を実行した実行結果が表示されます。

assert 式1 ;
assert 式1 : 式2 ;

javacコマンドでコンパイルする際、オプションに-source 1.4を指定することで、アサーションを有効にできます。指定しない場合は、アサーションは無効です。

javac -source 1.4 xxx.java

javaコマンドでプログラムを実行する際、オプションに-eaもしくは、-enableassertionsを指定することで、アサーションを有効にできます。指定しない場合は、アサーションは無効です。

java -ea xxx
java -enableassertions xxx

※ この他特定のパッケージ内のみアサーションを有効にするなど、アサーションの有効範囲を細かく指定することもできます。詳細はアサーションのJava APIドキュメントをご参照ください。

利用方法

事前条件、事後条件、クラスの不変条件

アサーションを利用する際の基準として、「事前条件」、「事後条件」、「クラスの不変条件」の各条件に合わせて利用することがよいとされています。各条件はすべてのケースにおいて当てはまるわけではありません、環境にあわせ条件の設定を行います。

「事前条件」
メソッドの引数が満たしておくべき条件。この条件がエラーになると、メソッド呼び出し前のプログラムコードにバグがあることを表します。
「事後条件」
メソッドの処理終了時点で満たしておくべき条件。この条件がエラーになると、メソッド内のプログラムコードにバグがあることを表します。
「クラスの不変条件」
クラスのオブジェクトが満たしておくべき条件。メソッド実行前と、メソッド実行後にこの条件を確認します。 メソッド実行前にこの条件がエラーになると、メソッド呼び出し前のプログラムコードにバグがあることを表します。メソッド実行後にこの条件がエラーになると、メソッド内のプログラムコードにバグがあることを表します。 不変条件の例としては、クラスのメンバ変数に正しい値が設定されているか。メンバ変数同士の関係は正しいか。などがあります。

publicなメソッドの引数チェックは行わない

publicなメソッドの引数チェックは、通常のプログラムコードの中で常に行われるべきであり、アサーションを利用して行うべきでないとされています。

プログラムで必要な処理をアサーションで行わない

プログラムで必要な処理をアサーションで行うべきではありません。変数xを10倍する処理があった場合、「assert x * 10 > 100;」と記載するとアサーションを利用しない場合10倍する処理が行われません。この場合は、「x = x * 10;」「assert x > 100;」と記載します。

利用例

アサーションの利用例を以下に記載します。引数x、yを持ち、xをy回分加算するcalNumメソッドにアサーションを設定した例です。

【例1】

public class ExAssert {
    public static void main(String[] args) {
        ExAssert object1 = new ExAssert();
        object1.calNum(5, 10);
    }

    void calNum(int x, int y) {
        int z = 0;
        //(1)事前条件
        assert x > 0 && y > 0:"xまたはyが0以下です。";

        //(2)変数xを変数y回、加算
        for (int i = 0; i < y; i++) {
            z = z + x;
        }

        //(3)事後条件
        assert z >= x && z >= y:"zがxまたはyより小さい値です。";

        System.out.println(z);
    }
}

解説1

  1. (1)事前条件として、引数x、yが0より大きな値であることを設定しています。0以下である場合、AssertionErrorが返されます。
  2. (2)forループを利用し、xをy回分加算しています。xをy回分加算した結果は変数zに代入されます。
  3. (3)メソッドの事後条件として、変数zが引数x、y以上であることを設定しています。x、y未満である場合、AssertionErrorが返されます。

【実行結果1】AssertionError無し

C:\source>javac -source 1.4 ExAssert.java

C:\source>java -ea ExAssert
50

C:\source>

【実行結果1】forループの処理をコメントアウトしてAssertionErrorが発生

C:\source>javac -source 1.4

ExAssert.java C:\source>java -ea ExAssert

#forループ処理が実行されていないため、事後条件に違反しAssertionErrorが返されています。
Exception in thread "main" java.lang.AssertionError: zがxまたはyより小さい値です 。
   at ExAssert.calNum(ExAssert.java:15)
   at ExAssert.main(ExAssert.java:4)

C:\source>

4アサーション