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