Wednesday, January 02, 2008

java.util.List の size() メソッドをループの範囲チェックでは呼び出さない方がいい

List をループで使用する場合、次のようなコードを書きがちだ。

List li = new ArrayList();
// この辺は省略
for(int i = 0; i < li.size(); i++) {
Object o = li.get(i);
}

これは、次のように書いた方がいい。

List li = new ArrayList();
// この辺は省略
for(int i = 0, n = li.size(); i < n; i++) {
Object o = li.get(i);
}

僕のマシンでこのループを 10億回まわしてみたところ、ループの都度 size() を呼び出すと 43秒ほどかかり、初期化のところで1回だけ呼び出すようにすると 25秒ほどかかった。

修正後の所要時間は修正前の 58% にまで下がっている。

また、ここでは List の要素にアクセスするのにイテレータではなく、get(int) メソッドを使っている。これがふさわしいのは、List の実装がランダムアクセスの場合だけだ。LinkedList などの場合は、ランダムアクセスではなくシーケンシャルアクセスなので、イテレータを使うべきだ。

以上のことは、Joshua Bloch 著 『Effective Java』 の29項に触発されて調べてみた。

No comments: