Don't use raw type in Java Generic


Effective Java Item 26 Raw type은 사용하지말라についてのまとめです.

Raw Typeとは?


まずJENICクラスまたはJENICインタフェースを定義しますタイプパラメータ(type parameter)がクラスとインタフェース宣言に使用される場合、JENICクラスまたはJENICインタフェースと呼ばれます.総称してジェニーンリックタイプ.
JENERICタイプが定義されている場合は、付属のRaw Typeも一緒に定義されます.ジェニーンリックタイプでタイプパラメータを全く使用しない場合を指します.List<E>の元のタイプはListです.ジェニーリックが来る前にコードと互換性があるように、私はまだそれを使用することができます.
private final Collection stamps = ...;
ただし、Stampではなく上記のコードを使用すると、エラーが発生することなくCoinがコンパイルされて実行されます.(Genericのメリットは利用できません.)
for (Iterator i = stamps.iterator(); i.hasNext();) {
	Stamp stamp = (Stamp) i.next();
    stamp.cancel();
}
上記のコードを変換するまで、エラーは見つかりません.エラーはできるだけコンパイル時に発見し、コンパイル時にすぐに発見することが望ましい.以上のように、Rawtypeを使用すると、実行時にのみエラーが検出されます.ClassCastExceptionが発生した場合は、Stampsへのコイン投入場所を検索するためにコード全体を参照する必要があります.
しかし、JENICを利用すれば、タイプ宣言自体がタイプの安定性を確保できる.
private final Collection<Stamp> stamps = ...;
これで、Coinオブジェクトを切手に入れるコードがあれば、コンパイル時にエラーを認識できます.
要するに,Raw Typeを用いるとGenericによる安定性と表現力が失われる.互換性のため、まだ存在しますが、使用すべきではありません.

元のタイプのListを使用するよりも、List<Object>を使用します。


リストなどの元のタイプは使用しないでくださいが、List<Object>などのすべてのクラスの親としてオブジェクトを使用することができます.違いは、List<Object>がコンパイラにすべてのタイプを許可することを明確に示すことである.ListをパラメータとしてRawタイプを受け入れる方法に渡すことはできるが、List<String>をパラメータとして渡すことはできない.これはジェニーリックのサブタイプルールに基づいています.List<Object>は元のタイプのサブタイプであるが、List<Stirng>のサブタイプではない.したがって、List<Object>などのパラメトリックタイプを使用するのとは異なり、List<Object>などの元のタイプを使用するとタイプが不安定になる.

要素が分からない場合は、Raw TypeではなくWildcardを使用します。


時々要素タイプを知らないRaw Typeを書きたい
2つのセット(Set)を受け取り、共通要素を返す方法を作成するとします.
次はgenericを使用する最初のユーザーが作成するコードです.
static int numElementsInCommon(Set s1, Set s2) {
	int result = 0;
    for (Object o1: s1) {
    	if(s2.contains(o1))
        	result++;
    }
    return result;
}
Raw Typeを使用しているため、この方法は安全ではありません.コードを改善するには、非限定ワイルドカードタイプを使用することをお勧めします.
static int numElementsInCommon(Set<?> s1, Set<?> s2) { ... }
上記の方法は最も一般的なパラメータ化設定タイプであり、任意のタイプを含んでもよい.ListSet<?>のタイプの違いは簡単で、Raw Typeはどんなタイプでもよいので、タイプ不変式を破壊しやすい.逆に、Setには任意の要素を加えることはできません.(Nullを除く)オブジェクトのタイプは、取り出し時に全く不明です.これらの制限を解除するには、限定されたワイルドカードタイプを使用します.

Raw Typeは本当に使えないのですか?


個人的なコラボレーションの場合はコンシステンシは使わないほうがいいですが、Effective Javaには確かに役に立つ例があります.

Class LiteralはRaw Typeを使用する必要があります。


A class literal is an expression consisting of the name of a class, interface, array, or primitive type followed by a . and the token class. The type of a class literal is Class. It evaluates to the Class object for the named type (or for void) as defined by the defining class loader of the class of the current instance.
クラス文字は、クラス、インタフェース、配列、およびベースタイプ名を表す表現です.class literalのタイプはSet<?>です.
class文字のパラメトリックタイプを無効にしました.Class , List.classClass Literalを単独で整理します

instanceofと併用する場合


実行時にJENICタイプ情報が消去されるため、instanceof演算子は非限定ワイルドカード以外のパラメトリックタイプに適用できません.
また,Raw Typeでも非限定ワイルドカードタイプでもinstanceofの動作は全く同じである.したがってinstanceof演算子を使用する場合、raw typeを使用するとより簡潔になります.

整理する


Raw Typeの概念を知って良いヒントを得た何気なくRaw Typeを乱用する可能性があります.これは意味のある定理で、いつ使うべきか、なぜ使うのかを知ることができます.
  • Raw Typeは過去のコードに存在し、Generic Typeを使用する
  • Genericタイプの安定性に使用します.
  • のコンパイル時間に、Generic Type情報が消去されます.
  • までに、エラーはコンパイルから除外されます.
  • パラメータを使用して要素のタイプを1つの範囲に制限したり、共通のパラメータ化をしたりしたくない場合は、WildCardタイプ(String[].class)を使用します.
  • ワイルドカードを補強するには、?のような境界ワイルドカードを使用することが望ましい.