Java開発において、Listコレクションは最も頻繁に使用されるデータ構造の一つです。特にArrayListとLinkedListはよく比較対象になりますが、これらのクラスをソースコードレベルで調査していると、興味深い違いに気づきます。ArrayListはRandomAccessというインターフェースを実装していますが、LinkedListにはその実装がありません。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
このインターフェースの中身を見てみると、実際には何も定義されていない空のインターフェースであり、Java 1.4から導入されたものです。
/**
* @since 1.4
*/
public interface RandomAccess {
}
目的と機能
Oracleの公式ドキュメントによると、これはいわゆるマーカーインターフェースであり、以下のように説明されています:
RandomAccessはList実装が高速(一般的に定数時間)なランダムアクセスをサポートしていることを示すために使用されるマーカーインターフェースです。
つまり、このインターフェースを実装することで、そのListが高速なランダムアクセスを提供することを示しています。
さらに、公式ドキュメントでは、RandomAccessを実装するListの場合、forループによる要素取得の方がイテレータを使用するよりも効率的であると明記されています。
実装例とパフォーマンス比較
以下のコード例で検証してみましょう。まず、forループを使用するメソッドとイテレータを使用するメソッドを作成します。
public static long measureForLoop() {
java.util.List<Integer> dataList = new java.util.ArrayList<Integer>();
for (int index = 1; index <= 50000; index++) {
dataList.add(index);
}
long startTimestamp = System.currentTimeMillis();
for (int position = 0; position < dataList.size(); position++) {
Object element = dataList.get(position);
}
long endTimestamp = System.currentTimeMillis();
return endTimestamp - startTimestamp;
}
public static long measureIteratorLoop() {
java.util.List<Integer> dataList = new java.util.ArrayList<Integer>();
for (int index = 1; index <= 50000; index++) {
dataList.add(index);
}
long startTimestamp = System.currentTimeMillis();
java.util.Iterator iterator = dataList.iterator();
while (iterator.hasNext()) {
Object currentElement = iterator.next();
}
long endTimestamp = System.currentTimeMillis();
return endTimestamp - startTimestamp;
}
mainメソッドでのテストコード:
public static void main(String[] arguments) {
long forDuration = measureForLoop();
long iteratorDuration = measureIteratorLoop();
System.out.println("ArrayList forループ処理時間:" + forDuration + "ms");
System.out.println("ArrayList イテレータ処理時間:" + iteratorDuration + "ms");
}
実行結果:
ArrayList forループ処理時間:1ms
ArrayList イテレータ処理時間:2ms
この結果から、forループによる要素アクセスの方がイテレータよりも処理時間が短いことが確認できます。これにより、RandomAccessインターフェースの効果が実際に現れていることがわかります。
ただし、現代のコンピュータ性能やJVMの最適化により、このようなパフォーマンス差は非常に小さく、特に小さなデータセットではほとんど無視できる程度です。したがって、日常的な開発では過度にこれらの手法のパフォーマンス差を気にする必要はなく、コードの可読性や保守性を優先することが望ましいです。