日々常々

ふつうのプログラマがあたりまえにしたいこと。

Listのループ

Listを全件ループして処理する場合、ぱっと思いつくところで3種類あります。

  • ループカウンタによるループ
  • Iteratorによるループ
  • 拡張for文によるループ(J2SE 5.0以降)

実装例

// なんらかのリストを取得する。
List<?> list = getList();

// ループカウンタ
for (int i = 0, n = list.size(); i < n; i++) {
    Object o = list.get(i);
    // 処理
}

// Iterator
for (Iterator i = list.iterator(); i.hasNext();) {
    Object o = i.next();
    // 処理
}

// 拡張for文
for (Object o : list) {
    // 処理
}

これら全て一長一短で、どれを使うかはその時々です。Listはインタフェースですので、パフォーマンスの観点からという理由で常に一つを選択することは出来ません。例えば、ループカウンタの使用がArrayListにおいては最も高速になりますが、LinkedListでは非常に遅くなります*1。逆に、Iteratorを使用するループでは、LinkedListがArrayListよりも早くなります。これはどちらも現実的な速度で処理されると思います。LinkedListが使用される可能性があるならば、ループカウンタは見合わせた方が良いかもしれません。

なお、拡張for文は内部的にはIteratorを使用するので、Iteratorの場合と大抵パフォーマンスに明確な差は出ないと思います。一応拡張for文のほうが早いはずなのですが、マシンの機嫌によって変わりますので、試行回数が少ないとIteratorの方が早い結果となるかもしれません。

今回のようにListインタフェースで取得する場合は、基本的に拡張for文を使用するべきだと思います。パフォーマンスを追及するならば、ListインタフェースではなくArrayListクラスやLinkedListクラス等、具象クラスとすべきだと思います*2

Listのインスタンスに何を使用するかは悩みどころだと思います。というか、悩むべきところだと思います。コードを書くときは、そのコードにどういう意味があるかを意識して書くべきであり、「List list = new ArrayList();」を定型句として扱うなんて、もってのほかです。

*1:件数が増えると現実的でない速度にまで低下します。

*2:とはいえ、これらはfinalなクラスではないので、オーバーライドされる可能性があることには注意したいところです。