effective java 輪読会 第7章 項目38-40

Post on 27-Jun-2015

332 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Effective Java 輪読会 第 6回(項目 38 ~ 40 )2014/2/12

開発部 野口

項目 38 パラメータの正当性を検査する

パラメータの正当性を検査する エラーが発生したらできるだけ速やかにエ

ラーを検出すべき メソッドはパラメータへの制約をメソッド本体の

初めに検査すべき

パラメータの正当性を検査しない場合

処理の途中で訳の分からない性外で失敗する メソッドは正常にリターンするが、何も言わ

ずに誤った結果を計算する メソッドは正常にリターンするが、いくつか

のオブジェクトを不正な状態のままにする 後になって、コードの全く関係のない箇所でエ

ラーを引き起こす 最悪!

例外を文書化する public のメソッドに対しては、パラメータ値

に関する制約が守られていない場合にスローされる例外を文書化する Javadoc の @throws タグを使用 IllegalArgumentException 、 IndexOutOfBou

ndsException 、 NullPointerException 等 文書化さえできれば、コードを書くのは簡単

アサーションを用いる 公開されていないメソッドに関しては、ア

サーションを用いてパラメータを検査する DataSpider では、独自のアサーション用ユー

ティリティクラス com.appresso.ds.common.fw.Assert を用いている

規則に対する例外 正当性検査のコストが高いか現実的でない かつ、正当性検査が計算の処理の中で暗黙に

行われる 例) Collections.sort(List) ただし、エラーアトミック性(項目 64 )に注意

が必要 失敗したメソッド呼び出しは、オブジェクトをそのメ

ソッド呼び出しの前の状態にしておくべき

注意:制約はよいものではない 制約がなくなるくらい、メソッドを一般的に

設計すべき 実際には、制約がやむをえない場合が多いの

で、その際は文書化し、チェックする

まとめ メソッドあるいはコンストラクタを書く際に

は、パラメータの制約を考える 制約を文書化する メソッド本体のはじめで明示的に検査し、制

約を強制する

項目 39必要な場合には、防御的にコピーする

Java は安全な言語 バッファオーバーランを始めとするメモリ破

壊エラーに対して、免疫がある (疑問:「免疫がある」ということ

は、 completely free というわけではない?)

それでも守る努力は必要 クラスのクライアントは、クラスの不変式を

破壊するために徹底した努力をする と想定して防御的にプログラムすべき

セキュリティを破ろうとする悪意のプログラマ よりも、むしろ使用者の単純なミスが問題

セキュリティホールの例 pp.178 Period クラス

コンストラクタで渡した Date を、渡したあとも変更できる( pp.179 )

start / end メソッドの戻り値を変更することで、Period の内部を変更できる( pp.180 )

セキュリティホールへの対処 コンストラクタで、防御的コピー

( pp.179 ) TOCTOU 攻撃に備えるため、コピーに対して正

当性を検査する サブクラス化に対処するため、 clone メソッド

を使用しない アクセッサ-でも、防御的コピー

( pp.180 )

本当の教訓 可能な場所では、オブジェクトの構成要素と

して不変オブジェクトを使用する 例) Date ではなく、 Date.getTime() の戻り

値( long )を用いる

トレードオフ パフォーマンス上のペナルティはありうる

クラスとその呼び出し元が同じパッケージの一部であるような場合には、防御的コピーを行わず、かわりにドキュメンテーションで済ませるといった手もある

制御の移転 パッケージ境界を越えるとしても、あえて防

御的にコピーしないケース ドキュメンテーションに制御の移転が必要で

あることを示し、クライアントはそれに従う 例)ラッパークラス

ラッパークラスでは、一般に制御を移転したあとにオブジェクトを変更した場合に、クライアント自身にのみ害を及ぼす

まとめ クラスがそのクライアントから得たり、クラ

イアントへ返したりする可変の要素を持っているならば、防御的にコピーする

コピーのコストが非常に高く、クライアントが要素を不適切に変更しないことを信頼できるなら、その旨をドキュメンテーションに示す

項目 40メソッドのシグニチャを注意深く設計する

メソッド名を注意深く選ぶ

理解可能 同じパッケージ内の他の名前と矛盾がない 広範囲のコンセンサスと矛盾がない

Java ライブラリーの API がガイダンスになる まあ、ところどころ矛盾もあるけど……。

大きさとか、歴史的な経緯とか

便利なメソッドを提供し過ぎたりしないようにする 個々のメソッドは、「自分の役割を果たす」こ

と 型がサポートしている個々の処理について完全

に機能すること 速記法は本当に頻繁に使用され、明らかに役に立つ場合だけ

特にインタフェースには注意 多くのメソッドを持つインタフェースはユーザお

よび実装者の人生を複雑にする人生、シンプルな方が(精神衛生上)よい

長いパラメータのリストは避ける

4 個以下を目標に マジックナンバー 7±2 という説もありますね

同じ型のパラメータが何個も続くのは特に有害 順序を間違えてもコンパイルエラーにならない

パラメータリスト短縮法その1

メソッドを複数のメソッドに分割する 直交性を増加させ、メソッド数を減らすこともで

きる 例) java.util.List の subList メソッド

と、 indexOf / lastIndexOf メソッド

パラメータリスト短縮法その2

ヘルパークラス static のメンバークラス 例)カードゲームを表すクラスにおいて、ランク

とスートを常に同時に扱っているなら、「カード」ヘルパークラスを導入する

パラメータリスト短縮法その3

ビルダーパターンの応用 saucepan.water(400).sugar(5).salt(10).cube

(Cube.Chicken, 2).cook()

パラメータ型に関しては、クラスよりインタフェースを選ぶ たとえば、 HashMap ではなく Map を使う

たまたま HashMap 以外の Map を持っているクライアントを煩わせずにすむ

参照)項目 52 インタフェースでオブジェクトを参照する『実装パターン』( Kent Beck )にも同様の議論が

ありました

boolean パラメータより 2 つの要素を持つ enum 型を使用する 読みやすくなる IDE のコード補完を活用できる オプションを追加しやすい メソッドへのリファクタリングも可能

top related