Effective Java 第 2 版:第 5 章 項目 24, 25

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

型パラメータを書いていないなどの理由で、コンパイル時に無検査警告が出ることがある。 無検査警告は全て取り除くべきである。 なぜなら、全ての警告を取り除けば、そのコードは型安全であると保証できるからである。

もし、警告を取り除くことができなくても、そのコードが型安全であると確かに示せるならば、

@SuppressWarnings("unchecked")

というアノテーションにより、警告を抑制することができる。 このアノテーションは、できるだけ小さいスコープに対して用いるべきである(一つの変数宣言など)。 また、警告を抑制するときは、他者が理解しやすいように、コメントに理由を書くべきである。

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

ジェネリックな配列は作れないという話。 まずイレイジャについて説明したあと、なぜジェネリックな配列が作れないか説明する。

イレイジャ

イレイジャはジェネリックスを実現するための機構である。 型パラメータを持つ宣言は、コンパイル時にイレイジャによって型パラメータの情報が消される。 例えば、以下のコードを考える。

List<Integer> list= new ArrayList<Integer>();

このコードは、実行時は以下のコードと見なされる。

List list = new ArrayList();

イレイジャで実行時は型情報を破棄することで、ジェネリックスを使っていない過去のコードと相互運用できるようにしてある。

なぜジェネリックな配列は作れないか

以下のコードの 1 行目にあるような、ジェネリックな配列は作れない。

List<String>[] stringListss = new List<String>[1];    // ここでコンパイルエラー
List<Integer> intList = Arrays.asList(42);
Object[] objects = stringLists;
objects[0] = intList;
String s = stringLists[0].get(0);

このコードがコンパイルできるとする。 このとき、実行時のコードは以下の通りとなる。

List[] stringListss = new List[1];
List intList = Arrays.asList(42);
Object[] objects = stringLists;
objects[0] = intList;
String s = stringLists[0].get(0);

1, 2 行目では、イレイジャによって、型パラメータの情報が消されている。 また、3 行目で配列の共変性により stringListsobjects に代入されている。 これより、4 行目において、Integer 型の要素からなるリストが String 型の要素からなるリストに代入されてしまっている。 こうなると、5 行目で Integer から String への誤ったキャストが起こり、ClassCastException が投げられる。 以上の処理が起きるのを防ぐために、 ジェネリック配列はコンパイルエラーとなる。

結論

以上のようなことがあるので、ジェネリックスを使いたいときは、List などのコレクション型を利用する方がよい。

参考文献

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)