Javaでは配列よりリスト(ジェネリクス)を選ぶ

Effective Javaを読んでいる。Javaでは、配列は使わずにリスト(ジェネリクス)を使えということだった。
 

ジェネリクスとは

ジェネリクスとは、「総称性(Genericity)」「ジェネリック・プログラミング」とも呼ばれるプログラミング技法で、 オブジェクト指向とは異なるパラダイムからきたものである。データの型に束縛されず、型そのものをパラメータ化して扱うことができる。Javaでは主にコレクションクラスに導入されている。
 

変性とは

何故、配列よりリストを使うことが推奨されるのかを理解するために、先に変性について理解しておく必要がある。

  • 共変 (covariant): 広い型(例:double)から狭い型(例:float)へ変換すること。
  • 反変 (contravariant) : 狭い型(例:float)から広い型(例:double)へ変換すること。
  • 不変 (invariant): 型を変換できないこと。

 
ここにおける「広い」「狭い」とは、機能が「広い」「狭い」という意味で、例えば、double型(64bitまで表現可能な小数を定義できる型)をfloat(32bitまで表現可能な小数を定義できる型)に変換する場合などは、共変 (covariant)である。逆にfloatをdoubleに変換する場合などは、反変 (contravariant)である。不変 (invariant)については、そのままの意味なので説明は省く。
 

配列よりリストを選ぶ

Javaの配列とリスト(ジェネリクス型)の最も大きな違いは、次の点である。

  • 配列は共変である。
  • リスト(ジェネリクス型)は不変である。

 
以下より、それぞれの点について詳しく説明する。
 

配列は共変

配列は共変という性質を持っているので、Object[]にString[]を代入することが出来る。つまり、String[]はObject[]のサブクラスである。

String[] strArray = {"test1", "test2"};
Object[] objArray = strArray; // 配列は共変なので代入可能
objArray[0] = new Integer(3); // java.lang.ArrayStoreException

 

リスト(ジェネリクス型)は不変

一方の、リスト(ジェネリクス型)は不変なので、Object[]にString[]を代入することが出来ない。

List<String> strList = new ArrayList<String>();
strList.add("test1");
strList.add("test2"); 
List<Object> objList = new ArrayList<Object>();
objList = strList; // コンパイルエラー

 
配列やリストでは、型の混入は避けたい現象である。配列の場合は、実行時に不正な型が混入した場所で例外(java.lang.ArrayStoreException)を投げてくれる。一方、リスト(ジェネリクス型)では、コンパイル時にエラーとなる。実行時ではなく、コンパイル時にきちんと例外を投げてくれると、バグの混入場所が特定が容易である。
 
上記を踏まえて、Javaでは配列ではなく、リスト(ジェネリクス型)を使用することを推奨する。
  
 
以上
 
 
参考
書籍 Effective Java
共変性と反変性 (計算機科学) – Wikipedia
今まで知らなかった 5 つの事項: Java コレクション API の場合: 第 1 回
なぜ Java の配列は共変で、Generics は共変ではないのか – sinsengumi血風録

Article written by

One Response

  1. ジェネリクスとは
    ジェネリクスとは at |

Comments are closed, but trackbacks and pingbacks are open.