ArrayListの全要素取得パフォーマンス比較

java.util.List型(ArrayListインスタンス化)コレクションを全要素取得するような処理の以下の3つについてパフォーマンスを比較してみました。

  • get(index)でアクセス
  • Iteratorを取得して使用
  • 拡張for文

なお、比較には拙作のツールを使用しました。

http://sourceforge.jp/projects/java-cpt/wiki/FrontPage

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import jp.sourceforge.javacpt.ComparativePerformanceTest;
import jp.sourceforge.javacpt.ComparativePerformanceTestHelper;

public class LoopSample
{
	public static void main(String[] args) throws Exception
		int executeTimes = 100000;
		LoopSample instance = new LoopSample();
		ComparativePerformanceTest test = ComparativePerformanceTestHelper.initialize(
				executeTimes, instance);

		// 対象のListオブジェクト
		List<Object> target = new ArrayList<Object>();
		for (int i = 0; i < 100; i++)
			target.add(new Object());

		// get(index)でアクセス
		String indexLoop = "indexLoop";
		long indexLoopResult = 0;
		// Iteratorを取得して使用1
		String iterLoop1 = "iterLoop1";
		long iterLoop1Result = 0;
		// Iteratorを取得して使用2
		String iterLoop2 = "iterLoop2";
		long iterLoop2Result = 0;
		// 拡張for文
		String enhancedForLoop = "enhancedForLoop";
		long enhancedForLoopResult = 0;

		// 10回実行
		for (int i = 0; i < 10; i++)
		{
			indexLoopResult += ComparativePerformanceTestHelper.invoke(test, indexLoop,
					indexLoop, List.class, target);
			iterLoop1Result += ComparativePerformanceTestHelper.invoke(test, iterLoop1,
					iterLoop1, List.class, target);
			iterLoop2Result += ComparativePerformanceTestHelper.invoke(test, iterLoop2,
					iterLoop2, List.class, target);
			enhancedForLoopResult += ComparativePerformanceTestHelper.invoke(test,
					enhancedForLoop, enhancedForLoop, List.class, target);
		}

		// それぞれ平均値を出力
		System.out.println(indexLoop + " : " + indexLoopResult / 10);
		System.out.println(iterLoop1 + " : " + iterLoop1Result / 10);
		System.out.println(iterLoop2 + " : " + iterLoop2Result / 10);
		System.out.println(enhancedForLoop + " : " + enhancedForLoopResult / 10);
	}

	public void indexLoop(List<Object> target)
	{
		int len = target.size();
		for (int i = 0; i < len; i++)
		{
			Object each = target.get(i);
		}
	}

	public void iterLoop1(List<Object> target)
	{
		for (Iterator<Object> iter = target.iterator(); iter.hasNext();)
		{
			Object each = iter.next();
		}
	}

	public void iterLoop2(List<Object> target)
	{
		Iterator<Object> iter = target.iterator();
		while (iter.hasNext())
		{
			Object each = iter.next();
		}
	}

	public void enhancedForLoop(List<Object> target)
	{
		for (Object each : target)
		{

		}
	}
}

結果としては以下の通りです。

indexLoop : 342
iterLoop1 : 839
iterLoop2 : 845
enhancedForLoop : 842

indexLoop : 328
iterLoop1 : 726
iterLoop2 : 712
enhancedForLoop : 712

indexLoop : 304
iterLoop1 : 720
iterLoop2 : 707
enhancedForLoop : 731

要素の取得部分に限ってみると、indexを指定してアクセスする方が2倍以上高速であることが分かります。

ループの中の処理内容によっては誤差の範囲内といえますが、共通ライブラリや頻繁に呼び出される処理を実装するときは、少し意識しておいた方がいいのかもしれません。


追記:(8/23)

内容の割にサンプルがどうも冗長だったので、ヘルパークラスをつくってよりシンプルにしました。