Effective Javaを読んて勉強してみようと思いましたが私にとっては難しいものでした。そこでじっくりとコードを打ち込んで理解しようと思いましたがコードが断片的であり、すんなり理解できなかったので、コードの省略部分を想像に任せ動くようにして、理解を深めようと思います。
本の1ページ目から始めればいいのですが、勉強会に途中から参加することになり、項目26から始めます。またこの記事は、記述されていない省略されたコードを補完することが目的で、何か技術的な説明をするのが目的なので、本を持っていないと理解できないことが多くあると思います。
1.本記事の対象の項目とページ
第5章 ジェネリックス 項目26 原型を使わない p120
2.コードスニペットを動くように補完したコード
p120上段部分で記述されている「やってはいけないコード」のスニペットを以下のとおり書き加えて、本書に書かれているエラーを吐き出すことができるようにしました。
次のコードは、main()メソッドを含むクラスです。本に記述されたコードスニペットを含んだStampCollectionクラスのインスタンスを生成します。
// p120 item26 やってはいけないなコード
public class Item26_3 {
public static void main(String[] args) {
StampCollection stampCollection = new StampCollection();
stampCollection.addStamp();
stampCollection.showCollection();
}
}
p120に記述されたコードスニペットを補完したコードを記述したクラスです。
本の中で 「private final Collection stamps =・・・」と書かれた「・・・」の部分は、Collectionインタフェースを実装したクラスなら何でも良さそうなので、一番ポピュラーなArrayList()を選びました。試してはいませんが、他にもLinkedListクラスやHashSetクラス、TreeSetクラスでもいいと思います。もしこれらのクラスを選んだら、本クラス後半のメソッドの内容が変わると思います。この辺は「川場著 新わかりやすいJava オブジェクト指向編p342」を参照しました。
public class StampCollection {
// 私の切手コレクション。Stampインスタンスだけを含む。
private final Collection stamps = new ArrayList();
public void addStamp() {
stamps.add(new Stamp(150, "山"));
stamps.add(new Stamp(250, "川"));
// 切手コレクションへのコインの誤った挿入
stamps.add(new Coin(100, "花")); // 「java: 不適合な型: CoinをStampに変換できません:コンパイルエラー
}
public void showCollection(){
// 原型のイテレータ型 - これをやってはいけない!
for ( Iterator i = stamps.iterator(); i.hasNext(); ) {
Stamp stamp = (Stamp)i.next();
//stamp.cancel();
System.out.println(stamp.toString());
}
}
}
上記のコードで__cancel()__が何か特別な意味があるのか疑問に思いteratailで質問したところ、何の意味もないとのことでしたので、コメントアウトしました。もし意味のないコードなら、悩むので記述して欲しくありませんでした。
次のStampクラスは切手コレクションのインスタンスstampsに登録する切手を表すデータクラスです。本の中では特にクラスの中身を指定していなかったので、とりあえず金額と絵柄のデータを持つことにしました。また登録したstampクラスのインスタンスの内容を表示できるようにtoString()メソッドを持っています。
public class Stamp {
private int value;
private String design;
public Stamp(int value, String design){
this.value = value;
this.design = design;
}
@Override
public String toString() {
return "Stamp{" +
"value=" + value +
", design='" + design + '\'' +
'}';
}
}
次のcoinクラスは、切手コレクションに誤って登録する切手のデータクラスです。クラスの作りはStampクラスと同じです。いっそのことStampクラスとの共通部分をインタフェースにすればいいかもしれません。
public class Coin {
private int value;
private String design;
public Coin(int value, String design){
this.value = value;
this.design = design;
}
@Override
public String toString() {
return "Coin{" +
"value=" + value +
", design='" + design + '\'' +
'}';
}
}
これらのコードをコンパイルすると、本の記述どおり警告と実行時エラーを生じました。
3.このようにしましょうのコードスニペット部分
本書120ページ後半に書かれている、このようにしましょうの部分。下のようにStampCollectionクラスの8行目に実パラメータを加え、
private final Collection<Stamp> stamps = new ArrayList<>();
と変更すれば、コンパイルエラーを生じることができますし、IntelliJなどのIDEを使用していればコードを書きながらエラーを見つけることができます。なぜコンパイルエラーを生じさせた方がいいかについては、本書を読んでください。
また本書には記述されていませんが、19行目を次のようにIteratorに実パラメータを加えるように変更すると、i.next()の前に記述していた(satamp)のキャストが不要になりうっかりミスがなくなります。(ArrayListの後ろの実パラメータ記述していませんが、jdkが型推論してくれるので省略しています。もちろんArrayListと記述してもよいです。)
for ( Iterator<Stamp> i = stamps.iterator(); i.hasNext(); ) {
Stamp stamp = i.next();
以上、