6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

EffectiveJava読書会4日目

Last updated at Posted at 2014-04-25

#ジェネリクス
##項目23 新たなコードで原型を使用しない

Collection.java
 //悪い例
 private final Collection stamps =...;
 //良い例
 private final Collection<Stamp> stamps = ...;
 }

原型がだめな理由

  • 誤ったオブジェクトを挿入→実行時にClassCastException

ジェネリク型の利点

  • 誤ったオブジェクトを挿入→コンパイル時にエラー
  • 要素を取り出す際にキャストする必要がない

###要素がわかっていない場合は非境界ワイルドカードを利用する

ジェネリックを利用したいけど、パラメータが何かわからない
→非境界ワイルドカードを利用する

Collection.java
 //悪い例
 static int numElementsInCommon(Set s1, Set s2){
     int result = 0;
     for (Object o1 : s1)
         if (s2.contains(o1))
             result ++;
     return result;
 }
  • Setだったらどんな要素でも挿入可
  • Set>にはいかなる要素も挿入不可

###結論
原型を利用せずにジェネリック型を利用する

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

(経験が浅いうちは)ジェネリックを多用すると無検査キャスト警告が多発します

  • 取り除くことが可能なら無検査警告を取り除く
  • 警告を取り除くことができない、でも型安全であることは明確、@SuppressWarnings("unchecked")アノテーションで警告を抑制する
  • @SuppressWarnings("unchecked")アノテーションを利用する場合、スコープはできるだけ小さくする
  • 安全である理由をコメントとして残す

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

###配列

  • 共変

    SubがSuperのサブタイプならSub[]がSuper[]のサブタイプ
  • 具象化

    実行時に型要素を既知かつ強制

###リスト

  • 不変
  • イレイズ

    コンパイル時のみ要素の型を強制、実行時には型情報を破棄
ArrayAndAllayList.java
 //配列の場合 実行時に失敗
Object[] objectArray = new Log[1];
objectArray[0] = "I don't fit in";

 //リストの場合 コンパイル時に失敗
List<Object> ol = new ArrayList<Long>();
ol.add("I don't fit in");


リストはコンパイル時の型安全性を提供

###結論
配列を利用せずにリストを利用する

###ジェネリック型の配列、パラメータ化された型の配列、型パラメータの配列は許可されていない

new List<E>[], new List<String>[], new E[]

##項目26 ジェネリック型を使用する

###自作のクラスをジェネリックにする利点

  • 型安全性を保証
  • クライアントが自作クラスを利用時に明示的なキャストが不要

###配列で実現されているクラスをジェネリックスに変換する場合

例) 項目6 のStackStack<E>に変換

####2つの方法

  1. Object配列を生成して、ジェネリック型配列へキャスト
  2. 型パラメータ配列のフィールドをObject[]にする

##項目27 ジェネリックメソッドを使用する

###クラスと同様メソッドもジェネリックメソッドに変更可能

Union.java
 //原型利用
public static Set union (Set s1, Set s2){
    Set result = new HashSet(s1);
    result,addAll(s2);
    return result;
}


//ジェネリックメソッド
public static <E> Set<E> union (Set<E> s1, Set<E> s2){
    Set<E> result = new HashSet<E>(s1);
    result,addAll(s2);
    return result;
}

上記のジェネリックメソッドの制限

  • 3つのSetの型が全て同じでなければならない

→コンパイラが型推論できる

インスタンス生成例
Map<String, List<String>> anagrams = new HashMap<String, List<String>>()

以下を利用すれば簡単になる
//ジェネリックstaticファクトリーメソッド public static <K,V> HashMap<K,V> newHashMap(){ return new HashMap<K,V> }

繰り返しの宣言不要
Map<String, List<String>> anagrams = newHashMap()

##項目28 APIの柔軟性向上のために境界ワイルドカードを使用する

Stack.java
 //ワイルドカード未使用
public void pushAll (Iterable<E> src){
    for(E e : src);
        push(e);
}


 //ワイルドカード使用
public void pushAll (Iterable<? extends E> src){
    for(E e : src);
        push(e);
}


 //ワイルドカード未使用
public void popAll (Collection<E> dst){
    while(!isEmpty());
        dst.add(pop());
}


 //ワイルドカード使用
public void pushAll (Collection<? super E> dst){
    while(!isEmpty());
        dst.add(pop());
}

##項目29 型安全な異種コンテナーを検討する

What?
ひとつのコンテナで、複数の型の要素を、型安全を保証しつつ取り扱う。

Why?
単一要素を取り扱うコンテナではまかないきれない、柔軟性が必要な場合がある。

Example?
データベースの行は任意の数の多くの列を持っており、型安全な方法でそれらすべての列をアクセスしたい。

呼び出し側

Favorites.java
 //型安全な異種コンテナーパターン
public Class Favorites {
    public <T> void putFavorites (Class<T> type, T instance);
    public <T> get Favorites<Class<T> type>;
}

クライアント側

Clents.java
public static void main (String[] args) {

     Favorites f = new Favorites();
     f.putFavorite(String.class, "Java");
     f.putFavorite(Integer.class, 0xcafebade);
     f.putFavorite(Class.class, Favorite.class);

     String favoriteString = f.getFavorite(String.class);
     int favoriteInteger = f.getFavorite(Integer.class);
     Class<?> favoriteClass = g.get(Class.class);
     
}

実装

Clents.java
public class Favorites {
    private Map<Class<?>, Object> favorites = 
         new HashMap<Class<?>, Object>();
    
    public <T> void put Favorite(Class<T> type, T instance){
        if (type == null)
            throw NullPointerException ("Type is null");
        favorites.put(type, instance);
    
    public <T> getFavorite(Class<T>, type) {
        return type.cast(favorites.get(type));
    }

}


###制限

  • 原型
  • 具現化不可能型

###型を制御

What
メソッドに渡す型を制限したい場合がある。

How

境界型トークンを導入する。
境界型パラメータか、境界ワイルドカードを利用する。

まとめ

ひとつのコンテナで、複数の型を安全に管理できる。
そのための方法は、キーにClassオブジェクト(=型トークン)を使用することである。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?