Java

Assertion 機能

Documentation Contents
注: この文書は、Java 2 SDK 1.4 Beta 2 の付属文書を和訳したものです。
Back to:

概要

assertion は真偽値を含む文として知られ、式が実行さ れる時点で真であるべきだとプログラマが信じる式が書かれます。 例えば、データバッファからすべての引数をアンマーシャルした 後、プログラマはそのバッファに残っているデータのバイト数は 0 だと仮定するでしょう。システムは、真偽式を評価して、もし 偽であればエラーを報告します。真偽式が本当に真となることを 確認することで、システムはプログラムについてのプログラマの知識を確証し、 それによってプログラムにエラーがない可能性を強めます。

性能を上げるために assertion チェックを無効化できます。プ ログラムの開発とテスト中は assertion チェックを有効にして おき、実際に使用する段階では無効化することが一般的です。

assertion は無効化されることがあるので、プログラムは assertion 中の真偽式が評価されることを仮定してはいけません。 そのため、これらの式は副作用を持つべきではありません。換言 すれば、こういった式は、評価が完了した後で観測され得る状態 に影響を与えるべきではありません。ある assertion 中の真偽 式が副作用を持つことは不正なことではありませんが、一般によ いことではありません。assertion の真偽式に副作用があると、 assertion が有効か無効かによってプログラムの振る舞いが変わっ てしまうことがあるからです。

同様に、public メソッドの引数チェックに assertion を使うべ きではありません。引数チェックは一般にはメソッドの責任であ り、この責任は assertion の有効無効に関わらず遂行されなけ ればなりません。引数チェックに assertion を使うことにはさ らに別の問題もあります。誤った引数は IllegalArgumentException、IndexOutOfBoundsException、 NullPointerException といった実行時例外を引き起こすべきで す。しかし、assertion の失敗は例外を throw しません。

より詳しく知るには、以下のリンクを辿って下さい:


コンパイル

javac コンパイラに assertion を含むコードを処理さ せるには、-source 1.4 コマンドラインオプショ ンを使う必要があります。例:
javac -source 1.4 MyClass.java

文法

Java 言語に新しいキーワードがひとつ追加されました。 assert キーワードのために文法規則がひとつ変更 され、ひとつ追加されました:
StatementWithoutTrailingSubstatement:
<All current possibilities, as per JLS, Section 14.4 > AssertStatement
AssertStatement:
assert Expression1;
assert Expression1 : Expression2 ;
assert 文のどちらの書式でも Expression1 は boolean 型でなければ ならず、そうでない場合はコンパイル時エラーが起きます。

セマンティクス

あるクラスにて assertion が無効化されている場合、そのクラ ス中の assert 文は何の効果も持ちません。assertion が有効に なっている場合、ひとつ目の式が評価されます。もし偽であった 場合、AssertionError が throw されます。もし assertion が (コロンに続けて) 2つ 目の式を持つ場合、この式は評価されて AssertionError のコン ストラクタに渡されます。2つ目の式がなければ、パラメータを とらないコントラクタが使われます。(もしひとつ目の式が真な ら、ふたつ目の式は評価されません。)

もしどちらかの式の評価中に例外が throw された場合、 assert 文はそこで完了し、この例外を throw します。


assertion の有効化と無効化

デフォルトでは assertion は無効化されています。有効化、無 効化のために 2つのコマンドラインオプションが用意されていま す。

次のスイッチは、様々な粒度で assertion を有効にします。

     java [ -enableassertions | -ea  ] [:<パッケージ名>"..." | :<クラス名> ]
引数がなければ、このスイッチによって assertion がデフォル トで有効になります。 引数がひとつ与えられた場合、引数が "..." で終 わっていればパッケージが指定されたとみなされ、assertion は そのパッケージとサブパッケージ内で有効になります。引数が単 に "..." ならば、カレントディレクトリ中の名前なしパッケー ジ内で有効になります。引数が "..." 同様に、次のスイッチは assertion を無効化します。
     java [ -disableassertions | -da ] [:<パッケージ名>"..." | :<クラス名> ]
これらのスイッチが複数組指定された場合、それらはクラスのロー ド時に順に処理されます。例えば、 com.wonbat.fruitbat パッケージ (とそのサブパッ ケージ) 中でだけ assertion を有効にしたい場合、次のコマン ドが使えます:
     java -ea:com.wombat.fruitbat... <Main Class>
com.wombat.fruitbat パッケージでは有効にして com.wombat.fruitbat.Brickbat クラスでは無効 としたい場合、次のコマンドになります:
     java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat <Main Class>
上記のスイッチは、すべてのクラスローダと (クラスローダを持 たない) システムクラスに適用されます。この規則にはひとつ例 外があります: 引数が与えられない場合、これらのスイッチはシ ステムクラスには適用されません。これによって、シス テムクラス以外の全クラスで簡単に assert をオンにできます。 全システムクラスで assert を有効にするためには、別のスイッ チが用意されています。
     java [ -enablesystemassertions | -esa ]
これと対称に、全システムクラスで assert を無効化するために 次のスイッチが用意されています。
     java [ -disablesystemassertions | -dsa ]

プログラム中で assertion の有効化や無効化を行う

たいていのプログラマは以下のメソッドを使う必要はないでしょ う。これらは、インタプリタやその他の実行環境を開発するプロ グラマのために用意されています。

クラスローダに対してデフォルトの assertion 状態を設定する

各クラスローダはそれぞれ デフォルト assertion 状態 を保持しています。この boolean 値は、このクラスローダ によって後に初期化されるクラスにて assertion が有効となる か無効となるかのデフォルトを決めます。新しく作られるクラス ローダのデフォルト assertion 状態は偽 (無効) です。これは ClassLoader クラスに新しく用意されたメソッドを呼び出すこと でいつでも変更できます:
     public void setDefaultAssertionStatus(boolean enabled);
あるクラスがロードされるとき、そのクラスのパッケージ名かク ラス名の assertion 状態についてクラスローダに対して (下記 の新メソッドを用いて) 指定されたことがあるなら、そういった 指示はクラスローダのデフォルトの assertion 状態よりも優先 されます。さもなければ、そのクラスの assertion 状態はクラ スローダのデフォルトの assertion 状態に従います。

パッケージとそのサブパッケージに対して assertion 状態を設定する

以下のメソッドを用いると、パッケージごとのデフォルトの assertion 状態を設定することができます。パッケージごとのデ フォルト値は実際にはそのパッケージだけでなくサブパッケージ にも適用されます。
 
     public void setPackageAssertionStatus(String packageName, boolean enabled);

クラスとその内部クラスに assertion 状態を設定する

以下のメソッドを用いると、クラスごとに assertion 状態を設定できます:
     public void setClassAssertionStatus(String className, boolean enabled);

クラスローダのデフォルトの assertion 状態をリセットする

以下のメソッドは当該クラスローダに対して設定された assertion 状態をクリアします。
     public void clearAssertionStatus();

使い方についての注意

この章に書いてあることは assert の仕様ではありません。 assert 機能の使用についての情報を提供することが目的です。 標準化コミュニティの用語で言うと、この章の情報は non-normative です。

ここでは assert 構文の適当な使用例と不適当な利用例を挙げま す。これらの例は徹底したものではありません。assert 構文の 意図された使用法を伝えることが目的です。

内部の不変条件

一般に、プログラムの挙動に関係する重要な挙動を表す短く頻繁 な記述は、assertion の適当な使い方です。

assertion 機能を使えない状況では、多くのプログラマは以下の 方法でコメントを使うでしょう:

    if (i%3 == 0) {
        ...
    } else if (i%3 == 1) {
        ...
    } else { // (i%3 == 2)
        ...
    }
不変条件を記述するには、コメントを assert に変更すべきです。 (assert が多分岐 if 文中の else 節を守るよう に) 上記の例を変更します:
    if (i % 3 == 0) {
        ...
    } else if (i%3 == 1) {
        ...
    } else {
        assert i%3 == 2;
        ...
    }
% オペレータは本来の mod オペレータではなく剰余を計算する ので値が負となることがあります。そのため、i が負の場合上記の assertion は失敗し得ることに注意して下さ い。

制御フローに依らない条件

assertion の使用に適したもうひとつの候補は default ケース を持たない switch 文です。

例えば:

    switch(suit) {
      case Suit.CLUBS:
        ...
        break;

      case Suit.DIAMONDS:
        ...
        break;

      case Suit.HEARTS:
        ...
        break;

      case Suit.SPADES:
        ...
    }
プログラマはおそらく、4つの case のうちひとつは常に実行さ れるということを当然に思うことでしょう。この仮定を試験する には、以下の default ケースを加えます:
      default:
        assert false;
より一般的には、実行が達しないとプログラマが仮定する箇所に 以下の文を記述します。
    assert false;
例えばこういったメソッドがあったと考えてください:
    void foo() {
        for (...) {
            if (...)
                return;
         }
         // 実行はここに達するべきではありません!!!
    }
最後のコメントを次の文で置き換えます:
    assert false;
このテクニックは注意深く使ってください。もしある文が実行さ れない (と JLS 14.19 で定義されている) なら、assert を記述 することでコンパイル時エラーに遭うでしょう。

事前条件, 事後条件, クラスについての不変条件

assert 構文は、契約による設計 (design-by-contract) のすべ てを満たす機能ではないながら、略式の当該プログラミングスタ イルには役立ちます。

事前条件

慣習的に、public メソッドの事前条件はメソッド中で明示的に チェックされ、結果は例外を用いて通知されます。例えば:
    /**
     * リフレッシュレートを設定します。
     *
     * @param  rate リフレッシュレート, 単位は frames per second。
     * @throws IllegalArgumentException rate <= 0 か
     *          rate > MAX_REFRESH_RATE の場合。
     */
     public void setRefreshRate(int rate) {
         // public メソッドの事前条件を守らせます
         if (rate <= 0 || rate > MAX_REFRESH_RATE)
             throw new IllegalArgumentException("Illegal rate: " + rate);

         setRefreshInterval(1000/rate);
     }
assert 構文が追加されたからといってこの慣習は影響を受けま せん。assert はこういった事前条件には不適当です。チェック がメソッドに埋め込まれていれば、assertion が有効か無効かに 関わらず、引数チェックは確実に行われます。さらにまた、 assert 構文は指定された型の例外を throw しません。

しかしもし、public ではないメソッドに事前条件があり、クラ スの使用者がそのクラスを用いて行うことに対して事前条件は何 も影響しないとクラスの作者が信じるなら、assertion は適当で す。例えば:

   /**
    * リフレッシュ間隔を設定します (正当なフレームレートに対応しなければなりません)。
    *
    * @param  interval ミリ秒で表したリフレッシュ間隔。
    */
    private void setRefreshInterval(int interval) {
        // public ではないメソッドで事前条件が守られていることを確認します
        assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE;

        ... // リフレッシュ間隔の設定
    }
MAX_REFRESH_RATE が 1000 より大きくて利用者が 1000 より大 きいリフレッシュレートを選んだ場合に、上記の assertion は 失敗するでしょう。これは実際は、ライブラリにバグがあること のあらわれです。

事後条件

public メソッドか否かに関わらず、事後条件のチェックは assertion で実装するのが最良の方法です。例えば:
    /**
     * Returns a BigInteger whose value is (this-1 mod m).
     *
     * @param  m the modulus.
     * @return this-1 mod m.
     * @throws ArithmeticException  m <= 0, or this BigInteger
     *         has no multiplicative inverse mod m (that is, this BigInteger
     *         is not relatively prime to m).
     */
    public BigInteger modInverse(BigInteger m) {
        if (m.signum <= 0)
            throw new ArithmeticException("Modulus not positive: " + m);
        if (!this.gcd(m).equals(ONE))
            throw new ArithmeticException(this + " not invertible mod " + m);

        ... // Do the computation

        assert this.multiply(result).mod(m).equals(ONE);
        return result;
    }
2つ目の事前条件 (this.gcd(m).equals(ONE)) を 計算前にチェックするのは無駄なので、実際にはチェックしない でしょう。この事前条件は、標準的なアルゴリズムでこの計算を 行うことで、その副作用としてチェックされます。

時折、処理後の事後条件チェックのために、処理に先だっていく らかのデータを保存しておく必要があることがあります。これは、 2つの assert 文と単純な内部クラスの助けによって可能となり ます。内部クラスはひとつ以上の変数の状態を保存して、処理の 後でチェックできるようにします。例えば、次のようなコード片 があったとします:

    void foo(int[] array) {
        // 配列の操作
        ...

        // この時点で、配列は操作前とまったく同じ順序を保っている
    }
このように変更することで、上のメソッドでは文章として書かれ ているだけの assertion を機能させることができます。
    void foo(final int[] array) {

        class DataCopy {
            private int[] arrayCopy;

            DataCopy() { arrayCopy = (int[])(array.clone()); }

            boolean isConsistent() { return Arrays.equals(array, arrayCopy); }
        }

        DataCopy copy = null;

        // 常に成功します; 配列のコピーを保存するという副作用を持ちます
        assert (copy = new DataCopy()) != null;

        ... // 配列の操作

        assert copy.isConsistent();
     }
この慣用句は、ひとつ以上のデータフィールドを保存できるよう に、また、処理前後の値に関する任意の複雑な assertion を試 験できるように、容易に一般化できます。

ひとつ目の assert 文 (これは副作用のためだけに実行されます ) は次のより明示的な記述に置き換えることができます。

    copy = new DataCopy();
しかしこれは、assert が有効かどうかに関わらず配列をコピー するので、無効化されたときには何のコストもかからないという assert の利点を損なっています。

クラスについての不変条件

上で述べたように、assertion は内部の不変条件をチェックする 目的に適当です。assertion の仕掛け自体は、それをどう用いる かという流儀を規定するものではありません。ときに、必要な制 約をチェックするたくさんの式を、ひとつの内部的なメソッドに まとめてそれを assertion から呼び出すようにすると便利です。 例えば、釣り合いのとれたツリーデータ構造を実装するという状 況を考えます。ツリーが本当にデータ構造に従って釣り合ってい るかをチェックする目的の private メソッドを実装するのは、 適当な方法でしょう。
    // このツリーが適当に釣り合っていれば true を返す
    private boolean balanced() {
        ...
    }
このメソッドはクラス中で不変の条件をチェックします。クラス 中のすべてのメソッドが完了する前後で、常に真となります。こ れを確認するためには、すべての public メソッドとコンストラ クタに対して return の直前に次の行を記述します:
    assert balanced();
同様のチェックを public メソッドの先頭にも記述することは一 般にやり過ぎです。ただ、データ構造がネイティブメソッドで実 装されている場合は、メソッド呼び出しの間に "ネイティブピア (peer)" がバグによって壊されてしまうことがあります。メソッ ド先頭での assertion 失敗は、こういったメモリ破壊が起きて しまったことを示します。同様に、状態を他のクラスから変更で きてしまうようなクラスでは、メソッド先頭で不変条件チェック を行うことが得策かもしれません。(より良い方法は、他のクラ スから状態が直接見えてしまうことのないようにクラスを設計す ることです。)

クラスファイルから assertion の痕跡を完全に取り除く

資源の量が厳しいデバイス向けに開発を行っているプログラマは、 クラスファイルから assertion を完全に取り除きたいと望むか もしれません。取り除いてしまうと assertion を有効にはでき なくなりますが、それによってクラスファイルのサイズは小さく なります。クラスのロードが速くなる可能性もあります。高品質 な JIT がない状況では、それによってメモリ消費量が減り、実 行性能が向上するかもしれません。

assertion 機能は、クラスファイルからの assertion の除去を 直接はサポートしていません。しかし、assert 文を "条件コン パイル" 慣用句 (JLS 14.19) と共に使うことは可能です:

     static final boolean asserts = ... ; // false なら assert を除去します

     if (asserts)
         assert <expr> ;
assert をこのように使うと、コンパイラがこれらの assert の すべての痕跡をクラスファイルから取り除くことが可能になりま す。資源の量が厳しいデバイス向けのコード生成を支援する目的 では、このような除去が推奨されます。

assertion が有効であることが必要な場合

ある種の重要なシステムのプログラマは、現場にて assertion が無効化されることのないことを保証したいかもしれません。下 記の慣用句を用いることで、assertion が無効化されたクラスの ロードを妨げることができます。
    static {
        boolean assertsEnabled = false;
        assert assertsEnabled = true; // 意図的な副作用!!!
        if (!assertsEnabled)
            throw new RuntimeException("Asserts must be enabled!!!");
    }

ソースコードの互換性

Java プログラミング言語に assert キーワードが加わったこと で、assert を識別子として使う既存のプログラムは不正なもの になりました。このキーワード追加は、しかし、既存のバイナリ (.class ファイル) を使う分には何も問題になりません。 assert を識別子として使えない言語仕様への移行を容易にする ために、コンパイラはこのリリースでは 2種の動作モードをサポー トしています。 assertion を有効にするには、以下のコマンドラインスイッチを使います。
    -source 1.4
このフラグが指定されない場合、ソースコードの互換性が尊重さ れ、振る舞いは "1.3" のものとなります。1.3 互換ソースとの 互換性サポートは、時間とともに廃止されていくでしょう。

設計についての FAQ

以下は、assertion 機能の設計に関するよくある質問集です。

設計についての FAQ - 一般的な質問

  1. なぜ assertion 機能を用意するのですか? 特別なサポー トなしの Java 言語だけで assertion をプログラムすることが できるのに。

    場あたり的な実装は可能ですが、それらは必然的に見苦しく (assertion それぞれに if 文が要ります)、非効 率的 (assertion が無効であっても条件は評価される) なものと なります。加えて、場あたり的実装は assertion の有効化、無 効化のためにそれぞれ固有の方法を持っていて、そのことが特に 現場でのデバッグ時の有用性を損ねています。こういった欠点が あったため、これまで assertion が Java 文化の一部となるこ とはありませんでした。Java プラットフォームに assertion サ ポートを追加することで、この状況を改善できる見込みがありま す。

  2. この機能がどうして言語への変更に値するのでしょう か? ライブラリを用いた方法ではなく。

    我々は、言語への変更は重大な取り組みであって、軽々しく着手 されるべきではないことを知っています。ライブラリを用いたア プローチも検討しました。しかし、無効化すればassertion の実 行時コストは無視できるということが必須だと思われました。こ れをライブラリで達成するには、それぞれの assertion を if 文としてハードコードすることをプログラマに 強制せねばなりません。多くのプログラマはそうはしないでしょ う。プログラマは if 文を省略して性能が犠牲となるか、その機 能は完全に無視されるかのどちらかだったでしょう。 assertion はジェームスゴスリン氏による最初の Java の仕様に 含まれていたことを付記します。満足な設計と実装をするだけの 充分な時間がなかったために、assertion は Oak の仕様から取 り除かれました。

  3. なぜ、Eiffel 言語に見られるような、事前条件、事 後条件、クラス不変条件をひと通り備えた契約による設計 (design-by-contract) の機能を用意しないのですか?

    そういった機能を提供することを検討しました。しかし、それを Java 言語に融合させるためには Java プラットフォームライブ ラリへの多大な変更を要し、また、新旧ライブラリ間の不整合も 大きくなりそうでした。大きな変更、不整合なしにできるとは思 えませんでした。さらにまた、そういった機能を追加してなお、 Java 言語の十八番であるシンプルさが保たれるという確信も持 てませんでした。すべてを考慮した結果、我々は単純な boolean assertion 機能がとても素直でリスクの小さい解決法だ という結論に至りました。boolean assertion 機能を言語に追加 したからといって、将来、契約による設計のひと通りの機能を加 えることができなくなったわけではないことを述べておきます。

    単純な assertion 機能は契約による設計スタイルのプログラミ ングを、限定された形で可能にします。assert 文は事後条件と クラス不変条件のチェックに適します。事前条件チェックは相変 わらずメソッド内で行うべきです。事前条件チェックは、API 仕 様書に書かれた特定の例外を throw します。 IllegalArgumentException や IllegalStateException といった 例外です。

  4. boolean assertion を追加する代わりとして、無効化 時にコードのブロック全体の実行を抑制するような assert のよ うな構文を用意することもできたはずです。なぜそうしなかった のですか?

    そういった構文を用意すると、プログラマは、本来は別メソッ ドに分離すべき複雑な assertion を構文中に書いてしまいがち です。

設計についての FAQ - 互換性

  1. 新しいキーワードは assert を識別子として使ってい る既存のプログラムで互換性の問題を起こさないのでしょうか?

    ソースファイルでは問題となります。(assert を識別子とし て使うバイナリはきちんと動作し続けます。) 移行を容易にする ために、移行期間中は assert を識別子として使い続けられるよ うな方策を述べました。

設計についての FAQ - 文法とセマンティクス

  1. なぜ Expression2 中に基本型を記述できるようにしているのですか?

    強いてこの式の型を制限する理由はありません。任意の型を 許すことで、例えばそれぞれの assertion に固有の整数値を結 びつけたいといったプログラマに便宜を与えられます。また、こ れによって、System.out.print(...) といった式を書けます。望 ましいことです。

設計についての FAQ - AssertionError クラス

  1. Expression2 を持たない assert 文が AssertionError を生成した場合に、なぜ、条件を 記述したプログラムテキストが詳細メッセージ (例えば "height < maxHeight") として使われないのでしょうか?

    そうすることで、ある場合には assertion の利用者側での利 便性が向上するかもしれません。しかし、その恩恵があろうと、 すべてのそれらの文字列定数を .class ファイルと実行時イメー ジに加えてしまうコストを正当化する理由にはなりません。

  2. なぜ AssertionError は、それを生成したオブジェク トに対してアクセスすることを許さないのでしょうか? 同様に、 なぜ assertion から AssertionError に対してメッセージでは なくて任意のオブジェクトを渡せるようになっていないのでしょ うか?

    それらのオブジェクトにアクセスできると、プログラマは assertion 失敗からの復帰を試みてしまうでしょう。それはこの 機能の目的に沿わない誤用です。

  3. なぜ AssertionError にはコンテクストにアクセスす る機能 (例えば getFile、getLine、getMethod) が用意されてい ないのでしょうか?

    この機能は Throwable によって最もうまく提供されていて、 assertion エラーからだけでなく、すべての例外、エラーから使 うことができます。我々はこの機能を提供するように assertion 機能の最初の導入と同じリリースで Throwable を改 良するという意図を持っていました。(訳注: Throwable#getCause, initCause が導入された。)

  4. なぜ AssertionError は RuntimeException ではなく て Error のサブクラスなのでしょうか?

    この問題は物議をかもしました。エキスパートグループは詳 細に議論し、次の結論に達しました。プログラマが assertion 失敗からの復帰を試みないようにするにはError の方が適当であ る、と。assertion 失敗の原因を追求することは一般には困難で あるかまたは不可能です。こういった失敗は、プログラムが "既 知の空間の外側 (outside of known space)" に作用していると いうことを示し、実行の再開を試みることはおそらく有害です。 また、メソッドは throw し得る RuntimeException の多くを ("@throws" doc コメントを通じて) 明記するという取り決めに なっています。メソッドの仕様に assertion が失敗し得る状況 を記述するというのはほとんど意味がありません。そういった情 報は仕様ではなく実装の細部に属し、実装から実装、リリースか らリリースに従って変わり得るものだとみなされています。

設計についての FAQ - assertion の有効化と無効化

  1. なぜ、assertion をオブジェクトファイルから完全に取 り除くというコンパイラフラグを用意しないのですか?

    実用性を高めるために、現場で assertion を有効にできるこ とには確固とした要求があります。それと同時に、開発者がコン パイル時にオブジェクトファイルから assertion を取り除く ことも可能でした。しかし assertion は (そうであるべきでは ないにも関わらず) 副作用を持つことができるため、そういった フラグがプログラムの振る舞いを著しく変えてしまうことがあり ます。正しい Java プログラムに対してはただひとつのセマンティ クスがあるべきだと考えられています。また、現場で assert を 有効にできるように assert をオブジェクトファイル中に残すこ とを我々は推奨したいのです。最後に、JLS 14.19 に記述されて いる "条件コンパイルのための慣用句 (conditional compilation idiom)" を利用することで、本当に望む開発者は完 全な除去を行えます。

  2. なぜ setPackageAssertionStatus は対象パッケージ だけでなくそのサブパッケージまで効果を及ぼすように決められ たのでしょうか?

    プログラマが本当にコードを系統立てるためにパッケージ階 層を用いるなら、階層的な制御が有用となります。例えば、 Swing のすべてに対して assertion を有効化、無効化すること が可能です。

  3. なぜ setClassAssertionStatus は assertion 状態を 設定するには遅すぎるタイミングで呼ばれた場合に (例えばその クラスがすでにロードされている場合)、例外を throw するので はなく真偽値を返すのですか?

    assertion 状態の設定が遅すぎた場合には何もしないことが 必要であるか望ましいです。例外は重すぎます。

  4. なぜ setDefaultAssertionStatus と setAssertionStatus メソッドはひとつのメソッドをオーバロー ドしないのですか?

    メソッドの名付け方を明快にする方がよいからです。

  5. なぜ、アプレットが assertion を有効化、無効化す ることを防ぐための RuntimePermission がないのですか?

    アプレットが assertion 状態を変えるために ClassLoader のメソッドを呼ぶ理由はないのですが、それを許すことに害はな いように思われます。最悪でも、アプレットは後にロードされる べきクラスの assert を有効にすることで弱いサービス不能 (denial-of-service) 攻撃ができるくらいです。また、アプレッ トはアプレットがアクセスできるクラスローダによってロードさ れるクラスに対してしか assert 状態を変えることはできません。 不審なコードがクラスローダへのアクセスを得てしまう ことを 防ぐ RuntimePermission はすでに存在します (getClassLoader)。

  6. なぜ、自クラスの assert 状態を問い合わせる構文を 用意していないのですか?

    そういった構文があると、人は複雑な assertion コードを書 きがちです。悪い例を挙げます:

        if (assertsEnabled()) {
            ...
        }
    
    また、現在の API を使って assert 状態を問い合わせることも 簡単なことです。もし必要だと思うなら:
       boolean assertsEnabled = false;
       assert assertsEnabled = true;  // 意図的な副作用!!!
       // ここで assertsEnabled は正しい値に設定されます
    

Copyright © 2002 Sun Microsystems, Inc. All Rights Reserved.

Sun
Java Software