Effective java 輪読会 第5章 項目23-25

35
Effective Java 輪輪輪 輪 4 輪輪 23 25 2013/1/8 輪輪輪 輪輪

Transcript of Effective java 輪読会 第5章 項目23-25

Page 1: Effective java 輪読会 第5章 項目23-25

Effective Java 輪読会 第 4回(項目 23 ~ 25 )2013/1/8

開発部 野口

Page 2: Effective java 輪読会 第5章 項目23-25

項目 23 新たなコードで原型を使用しない

Page 3: Effective java 輪読会 第5章 項目23-25

ジェネリック型 1 つ以上の型パラメータを宣言に持つクラス

やインタフェース ジェネリッククラス/ジェネリックインタフェー

ス 例) List<E> はジェネリックインタフェー

ス E は型パラメータ 「 E のリスト」と読む 単に List とも読む

Page 4: Effective java 輪読会 第5章 項目23-25

パラメータ化された型 クラス名やインタフェース名の後に、 <> で

囲んだ実型パラメータのリストが続くもの 例) List<String>

「文字列のリスト」と読む

Page 5: Effective java 輪読会 第5章 項目23-25

原型 実型パラメータを伴わないで使用されるジェ

ネリック型の名前 例) List<E> に対応する原型は List 原型 List は、ジェネリックスがプラット

フォームに追加される前のインタフェース型 List と同様に振る舞う

Page 6: Effective java 輪読会 第5章 項目23-25

リリース 1.5 より前のコレクション宣言

// Stamps インスタンスだけを含んでいるprivate final Collection stamps = … ;

stamps.add(new Stamp()); // これが想定している挿入stamps.add(new Coin()); // これもコンパイルエラーにならない

for (Iterator I = stamps.iterator(); i.hasNext();) { Stamp s = (Stamp) i.next(); // ClassCastException がスローされる}

Page 7: Effective java 輪読会 第5章 項目23-25

パラメータ化されたコレクション型( 1/2 )

private final Collection<Stamp> stamps = … ;

stamps.add(new Stamp()); // これは想定している挿入stamps.add(new Coin()); // これはコンパイルエラーになる

Page 8: Effective java 輪読会 第5章 項目23-25

パラメータ化されたコレクション型( 2/2 )

// キャストも不要にfor (Stamp s : stamps) {

... // 切手で何かをする}

for (Iterator<Stamp> i = stamps.iterator(); i.hasNext();) {

Stamp s = i.next(); // キャストなし... // 切手で何かをする

}

Page 9: Effective java 輪読会 第5章 項目23-25

間違えるのはどんなとき? java.sql.Date インスタンスのコレクション

に、 java.util.Date インスタンスを入れてしまうとか……。

Page 10: Effective java 輪読会 第5章 項目23-25

原型の使用 原型を使用すると、ジェネリックスの安全性

と表現力のすべてを失うことになる 原型は、移行互換性のために残されている

Page 11: Effective java 輪読会 第5章 項目23-25

List と List<Object> の違い List は、ジェネリック型検査が行われない

パラメータ List に List<String> を渡すことができる List<String> は List のサブタイプ

List<Object> は、どのような型のオブジェクトでも保持できることをコンパイラに明示的に伝えている List<Object> に List<String> を渡すことはできな

い List<String> は、 List<Object> のサブタイプでは

ない(!) 具体例は、 pp.110 を参照

Page 12: Effective java 輪読会 第5章 項目23-25

非境界ワイルドカード型 ジェネリック型を使用したいけれど、実際の

型パラメータが何であるか分からなかったり、気にしたりしない場合にクエスチョン記号を使用できる 例)ジェネリック型 Set<E> に対するワイルド

カード型は Set<?> 「何らかの型のセット」と読む どのようなセットも保持できる(!)

Page 13: Effective java 輪読会 第5章 項目23-25

Set<?> と Set の違い Set<?> は安全 Set は安全ではない Set<?> ( Collection<?> ) には、( null

以外の)いかなる要素も入れることができない

Set ( Collection )には、どのような要素も入れることができる

Page 14: Effective java 輪読会 第5章 項目23-25

例外 (1/2)

クラスリテラルでは、原型を使用しなければならない 例) List<String>.class ではなく、 List.class

を使用する必要がある ジェネリック型情報が実行時に消されているから

Page 15: Effective java 輪読会 第5章 項目23-25

例外 (2/2)

非境界ワイルドカード型以外のパラメータ化された型に対する instanceof 演算子の使用は許されていない やはり、ジェネリック型情報が実行時に消されて

いるから 非境界ワイルドカード型について

も、 instanceof の使用はできるが、原型に対して使用した場合と違いがない

原型を使用するのがよい

Page 16: Effective java 輪読会 第5章 項目23-25

まとめ (1/2)

新たなコードでは原型は使用しない 実行時例外となる可能性があるため

原型はジェネリックス導入前のコードとの互換性と相互運用のためだけに提供されている

Page 17: Effective java 輪読会 第5章 項目23-25

まとめ (2/2)

Set<Object> は任意の型のオブジェクトを含むことが可能なセットを表しているパラメータ化された型<安全>

Set<?> は何らかの不明な型のオブジェクトだけを含むことが可能なセットを表しているワイルドカード型<安全>

Set はジェネリック型システムから外れている原型<安全でない>

Page 18: Effective java 輪読会 第5章 項目23-25

項目 24 無検査警告を取り除く

Page 19: Effective java 輪読会 第5章 項目23-25

無検査警告

 

Set<Lark> exaltation = new HashSet();

Page 20: Effective java 輪読会 第5章 項目23-25

無検査警告を取り除く

取り除くことが可能なすべての無検査警告を取り除くこと すべての警告を取り除けば、コードが型安全であると

安心できる 実行時に ClassCastException が発生しない

Set<Lark> exaltation = new HashSet<Lark>();

Page 21: Effective java 輪読会 第5章 項目23-25

無検査警告を抑制する 以下の場合にの

み、 @SuppressWarnings("unchecked") アノテーションで警告を抑制する 警告を取り除くことができない 警告を起こしているコードが型安全

Page 22: Effective java 輪読会 第5章 項目23-25

SuppressWarnings アノテーション

個々のローカル変数宣言からクラス全体まで、どのような粒度でも使用できる

できる限り最小のスコープに対して使用すること 変数宣言、非常に短いメソッドやコンストラクタ

等 クラス全体には決して使用しない

重大な警告を隠蔽してしまうため

Page 23: Effective java 輪読会 第5章 項目23-25

ローカル変数宣言へアノテーションを移動させる

例) pp.114 toArray メソッド return 文は宣言ではないの

で、 SuppressWarnings アノテーションを付けることはできないが、ローカル変数を宣言することでスコープを最小限にすることができる

Page 24: Effective java 輪読会 第5章 項目23-25

@SuppressWarnings("unchecked") アノテーション @SuppressWarnings("unchecked") アノ

テーションを使用する時には、そうするのが安全である理由を述べるコメントを必ず追加する 他の人がコードを理解することを助ける 計算が安全ではなくなるような変更を誰かが行う

可能性を減らす コメントについて考えるうちに、やはり安全では

ないということに気づく可能性もある

Page 25: Effective java 輪読会 第5章 項目23-25

まとめ

無検査警告は重要、無視してはいけない 実行時の ClassCastException の可能性を表し

ている 取り除くことが不可能で、それが実際には型

安全であると明確に示せる場合のみ、最小限のスコープで警告を抑制する コメントにその理由を残す

Page 26: Effective java 輪読会 第5章 項目23-25

項目 25 配列よりリストを選ぶ

Page 27: Effective java 輪読会 第5章 項目23-25

配列とジェネリック型の違い 1 (of 2) 配列は共変( covariant )

Sub が Super のサブタイプならば、配列型 Sub[] は Super[] のサブタイプ

ジェネリックスは不変( invariant ) Type1 と Type2 に対して、 List<Type1> は

List<Type2> のサブタイプでもなければスーパータイプでもない

Page 28: Effective java 輪読会 第5章 項目23-25

共変な配列は実行時に失敗する

 

Object[] objectArray = new Long[1];objectArray[0] = “I don‘t fit in”; // ArrayStoreException <実行時エラー>

Page 29: Effective java 輪読会 第5章 項目23-25

不変なジェネリック型はコンパイル時に失敗する 

List<Object> ol = new ArrayList<Long>(); // 互換性のない型<コンパイルエラー>ol.add("I don't fit in");

Page 30: Effective java 輪読会 第5章 項目23-25

配列とジェネリック型の違い 2 (of 2) 配列は具象化されている

実行時にその要素型を知っていて、強制する ジェネリックスはイレイジャで実装されてい

る コンパイル時にのみ型制約を強制し、実行時には

要素の型情報を廃棄(イレイズ)する

Page 31: Effective java 輪読会 第5章 項目23-25

ジェネリック配列の生成が許されていない理由 型安全ではないから

例) pp.117 「なぜジェネリック配列生成が許されないのか」 もしこの例がコンパイルされてしまったら、行 (5)

で ClassCastException が発生する それを防ぐために、行 (1) でコンパイルエラーとな

Page 32: Effective java 輪読会 第5章 項目23-25

具象化不可能型

その実行時の表現がコンパイル時の表現よりも情報が少ない型

具象化可能なパラメータ化された型は、非境界ワイルドカード型のみ

非境界ワイルドカード型の配列の生成は許されているが、まれにしか有用ではない

Page 33: Effective java 輪読会 第5章 項目23-25

可変長引数について

可変長引数のメソッドでジェネリック型を使用した場合、警告が発生する

その場合、抑制するか、 API として可変長引数とジェネリック型の混在を避けるかする

Page 34: Effective java 輪読会 第5章 項目23-25

非ジェネリックスからジェネリックスへの変更例 pp.118 上部 ジェネリックスを使用しない簡約、

そして並行性の欠陥↓ pp.118 下部 ジェネリックスを用いず、並行性の欠陥もない簡約↓

pp.119 上部 簡約の単純なジェネリック版 - コンパイルされない↓

pp.119 下部 リストに基づく簡約 ここで synchronized(list) としているのは、 new

によるインスタンス生成がアトミックでないから? →そのはず。

Page 35: Effective java 輪読会 第5章 項目23-25

まとめ

配列は共変で具象化されている 実行時の型安全性を提供するが、コンパイル時の

型安全性は提供しない ジェネリックスは不変でイレイズされる

実行時の型安全性を提供しないが、コンパイル時の型安全性を提供する

配列とジェネリックスの混在によってコンパイル時エラーや警告が出る場合、配列をリストに置換することを考えるとよい