例外処理を考える(1)

プログラマにとって例外処理は避けて通れない厄介な問題です。今回はJavaでの例外処理について考えてみたいと思います。

はじめに、Javaの例外処理のための仕組みを整理しましょう。

try〜catch〜finally節

例外を発生させるコード(メソッド・コンストラクタ・もしくは自分で発生させる)を使う部分をtry節で括り、その例外への対処をcatch節に、例外の有無に関わらず行う処理をfinally節に書きます。

try {

    // 例外を発生させるコード

} catch (SomeException1 e) {

    // SomeException1が発生した場合の処理

} catch (SomeException2 e) {

    // SomeException2が発生した場合の処理

} finally {

    // 例外の有無に関わらず行う処理

}

異なる例外を処理するcatch節は複数並べて書くことができますが、発生した例外に対応するcatch節かどうかは上から順に判定されることになっているため、ある例外を処理するcatch節の次にそのサブクラスに当たる例外を処理するcatch節を書くことはできません。(到達不能コードとなります)

この複数書ける、というところが重要です。つまり対処する例外とその対処方法を選択できるということですね。

throws句

メソッドまたはコンストラクタが発生させる(投げる・スローするという)例外を宣言します。

メソッドまたはコンストラクタが例外をスローする可能性がある場合、その例外、もしくはそのスーパークラスである例外をすべて宣言する必要があります。ただし、チェックされない例外(後述)は宣言しなくても構いません。

throw句

自分で例外をスローするときに使います。Throwableクラス(Exceptionクラスのスーパークラス)のサブクラスであればスローすることができます。

例外クラス

例外そのものを表すクラスです。例外にはチェックされる例外とチェックされない例外があります。

チェックされる例外
RuntimeExceptionクラスのサブクラスでない例外
チェックされる例外をスローするコードを使う場合、try〜catch節で括って処理するか、外側のメソッドでthrows宣言しなければならない。
チェックされない例外
RuntimeExceptionクラスのサブクラスである例外
チェックされない例外をスローするコードを使う場合は、try〜catch節で括る必要はなく、throws宣言も必要ない。したがって、チェックされない例外の発生は必ずしも予測できない。

端的に言えば、チェックされる例外とは「なんらかの対処をしないとコンパイルできない例外」で、チェックされない例外とは「対処しなくてもコンパイルできる例外」です。

ここに重要なポイントがあります。

つまりチェックされる例外は、なんらかの対処をすべき・あるいは回復可能な余地があるかもしれない例外を表し、チェックされない例外は、対処する意味が無い・もしくは回復不可能な例外を表すということなのです。(少なくともそういう意図を持って言語設計されています)

assert句

アサーション/表明は例外処理機構そのものではありませんが、安全で見やすいコードを書くために役立ちます。

assertに続けて条件式と必要であればメッセージを書きます。実行時にアサーションが有効であり、かつ条件式が偽であればAssertionErrorが発生します。

ちなみにAssertionErrorはThrowableのサブクラスであるため、自分でスローすることもできます。

AssertionError <- Error <- Throwable

次回へ

まずは例外処理のための仕組みをまとめました。次回から具体的な方針について見ていきたいと思います。

コメントを残す