Effective Java 輪読会 第8回
(項目63~65)
2014/2/26
開発部 野口
項目63
詳細メッセージにエラー記録情報を含め
る
例外の文字列表現は、
後の分析のためにエラーを記録す
る
 プログラムがキャッチされなかった例外によ
り失敗した場合は、システムは自動的にその
例外のスタックトレースを表示する
 スタックトレースには、その例外の toString メ
ソッドの結果である例外の文字列表現が含ま
れる
すべてのパラメータと
フィールドの値を含める
 たとえば、IndexOutOfBoundsException には、下
記をすべて含める
 下限範囲
 上限範囲
 範囲内に収まらなかった実際のインデックス
不要なものは含めなくてよい
 スタックトレースは、ソースファイルと一緒
に分析されるもの
 例外のスロー箇所およびスタック上のすべてのメ
ソッド呼び出しのファイルと行番号が含まれる
 よって、長ったらしい説明は不要
例外の文字列表現と
ユーザレベルのエラーメッセージ
 ユーザレベルのエラーメッセージ
 エンドユーザに対してわかりやすくなければならない
 例外の文字列表現
 エラーを解析する際にプログラマやフィールドサービ
ス担当者が主に使用するためのもの
 アプレッソにおいては、開発者、サポートセンター、リセ
ラーの担当者の方……。
 疑問:特に DataSpider Servista では、製品の性質上(あるい
は、現状の課題として?)、エンドユーザが例外を目にし
て自身で対処することも多いので、例外の文字列をわかり
やすくすることに意義がある?
 できるだけエラーコードを出すようにしてます
例外のコンストラクタを工夫する
(1)
 IndexOutOfBoundsException は、このようなコンストラクタを持って
いればよかったのに……。
public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) {
// エラーを記録する詳細メッセージを生成する
super( "Lower bound: " + lowerBound + ", Upper bound: " + upperBound + ", Index: "
+ index);
// プログラミングによるアクセスのためにエラー情報を保存する
this.lowerBound = lowerBound;
this.upperBound = upperBound;
this.index = index;
}
例外のコンストラクタを工夫する
(2)
 エラー記録情報にアクセッサ-を提供する
 チェックされる例外は、特に
 エラーから回復するのに役立つ可能性がある
 参照)項目58 回復可能な状態にはチェックされる例
外を、プログラミングエラーには実行時例外を使用す
る
 チェックされない例外も、あった方がよい
 参照)項目10 toString を常にオーバーライドする
項目64 エラーアトミック性に努める
エラーアトミック性
 失敗したメソッド呼び出しは、オブジェクト
をそのメソッド呼び出しの前の状態にしてお
く
 このような性質を持つメソッドは、エラーアト
ミックであると呼ばれる
 特にチェックされる例外については重要(再び項
目58)
エラーアトミック性を達成する
方法
 不変オブジェクトを用いる
 操作を行う前にパラメータの正当性を検査す
る
 エラーを捕捉し、回復するコードを書く
 Copy and Swap イディオムを用いる
不変オブジェクトを用いる
 オブジェクトが不変ならば、エラーアトミッ
ク性はコストがかからない
 参照)項目15 可変性を最小限にする
操作を行う前に
パラメータの正当性を検査する
 あるいは、失敗するかもしれない部分が、オブジェクトを変
更する部分よりも前に行われるようにする
 例)TreeMap では、要素の追加前に検索を行い、その時点で
ClassCastException で失敗する(エラーアトミック性は保たれる)
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // もし検査がなければ、
// ArrayIndexOutOfBoundsException が 潜在!
return result;
}
エラーを捕捉し、
回復するコードを書く
 主に永続的な(ディスクに基づく)データ構
造に対して使用されている
 あまり一般的でない方法
 (Java の例外に対処する方法としては、という意
味だと思います)
Copy and Swap イディオムを用い
る
 オブジェクトの一時的コピーに対して操作を
行い、操作が完了したらオブジェクトの内容
を一時的コピーの内容で置き換える
 例)Collection.sort
達成可能ではない場合・
望ましくない場合
 たとえば ConcurrentModificationException が発生
したとき、回復は難しい
 既にオブジェクトの整合性が保たれていない可能
性が高い
 エラーは、例外とは反対に、一般には回復不
可能
 著しくコストや複雑さが増すとき、望ましく
ないかもしれない
まとめ
 メソッドの仕様の一部である例外は、オブ
ジェクトをメソッド呼び出しの前と同じ状態
にすべき
 そうでない場合、API ドキュメンテーションは
オブジェクトがどのような状態に置かれるの
かを明確に示すべき
See also:
 『Exceptional C++』(Herb Sutter)
 「例外安全」を掘り下げた名著
 ただし、ピアソン桐原の技術書からの撤退により、
日本語版は目下のところ絶版です……。
 丸善の活躍に期待!(のぞみうす)
項目65 例外を無視しない
例外を無視しないようにしよう
 火災警報を無視して警報を切ってしまうのと同
じ!
 やばすぎ
 例外は目覚まし時計じゃない
 最低でも、なぜ無視するのが適切なのかコメントすべ
き
try {
...
} catch (SomeException e) {
}
例外を無視するのが
適切かもしれない状況の例
 FileInputStream をクローズするとき
 ファイルの状態を変更していなければ、別に回復
する必要もない
 既に情報を読み出しているなら、あえて中断する
必要もない
 ただし、記録はしよう
 頻繁に発生していれば、問題を調査できる
適用範囲
 チェックされる例外
 回復できるはず、回復が期待されている
 回復しましょう
 チェックされない例外
 回復できなければ、せめて外側に伝播させて、速
やかに失敗させる
 問題の発生箇所と発見箇所は近ければ近いほどよいの
法則

Effective Java 輪読会 項目63-65