EnumMapがどれだけ早いか性能を測ってみた。
EnumMapとかいうEnumのみをキーにできるMapがあって、これがEnumの連番を使って高速に動作するらしい。(→Java プログラミング言語 - 列挙型)
ということでとりあえず性能を測ってみた。
結果
get | put | |
---|---|---|
EnumMap | 312ms | 490ms |
HashMap | 593ms | 921ms |
TreeMap | 334ms | 1490ms |
LinkedHashMap | 497ms | 690ms |
うん、まぁ、早いかな。> EnumMap。
なお、計測環境のCPUは Pentium D 2.79GHz, JDKは1.6.0_07です。
計測で使用したコード
計測で使用したコードは以下の通り。
// テスト用の列挙型 enum Test { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z } ・・・ // EnumMap final Map<Test, String> enumMap = new EnumMap<Test, String>(Test.class); for ( Test t : Test.values() ) enumMap.put( t, t.name()); // HashMap final Map<Test, String> map = new HashMap<Test, String>(Test.values().length); for ( Test t : Test.values() ) map.put( t, t.name()); // TreeMap final Map<Test, String> treeMap = new TreeMap<Test, String>(); for ( Test t : Test.values() ) treeMap.put( t, t.name()); // LinkedHashMap final Map<Test, String> linkedMap = new LinkedHashMap<Test, String>(Test.values().length); for ( Test t : Test.values() ) linkedMap.put( t, t.name()); // Mapからの取り出し処理 class GetTask extends Perf.Task<Void> { final Map<Test, String> map; GetTask( Map<Test, String> map ) { this.map = map; } @Override public Void run(int i) { for ( int j = 0; j < 500000; j++ ) { for ( Test t : Test.values() ) { map.get( t ); } } return null; } } System.out.println( Perf.perf( "get-EnumMap", 5, new GetTask( enumMap ) ) ); System.out.println( Perf.perf( "get-HashMap", 5, new GetTask( map ) ) ); System.out.println( Perf.perf( "get-TreeMap", 5, new GetTask( treeMap ) ) ); System.out.println( Perf.perf( "get-LinkedHashMap", 5, new GetTask( linkedMap ) ) ); // Mapへの登録処理 class PutTask extends Perf.Task<Void> { final Map<Test, String> map; PutTask( Map<Test, String> map ) { this.map = map; } @Override public Void run(int i) { for ( int j = 0; j < 500000; j++ ) { for ( Test t : Test.values() ) { map.put( t, t.name() ); } } return null; } } System.out.println( Perf.perf( "put-EnumMap", 5, new PutTask( enumMap ) ) ); System.out.println( Perf.perf( "put-HashMap", 5, new PutTask( map ) ) ); System.out.println( Perf.perf( "put-TreeMap", 5, new PutTask( treeMap ) ) ); System.out.println( Perf.perf( "put-LinkedHashMap", 5, new PutTask( linkedMap ) ) );
Perf.javaは以下です。
import java.util.ArrayList; import java.util.List; /** * 性能計測ユーティリティ */ public class Perf { /** * 処理の実行時間を計る * @param <R> 戻り値の型 * @param id 識別子 * @param count 試行回数 * @param task 処理 * @return 計測結果 * @throws Exception */ public static <R> Result<R> perf ( String id, int count, Task<R> task ) throws Exception { // 初回のクラスロード時間を抑制するため // 1度実行する task.before(-1); R result = task.run(-1); task.after(-1); List<Long> times = new ArrayList<Long>(); for ( int i = 0 ; i < count ; i++ ) { task.before(i); long start = System.currentTimeMillis(); task.run(i); times.add(System.currentTimeMillis() - start); task.after(i); } return new Result<R>( id, result, times ); } /** * 計測結果 * * @param <R> 戻り値の型 * * @version $Revision:$ * @author $Author:$ */ public static class Result<R> { /** * 結果 */ public R result; /** * ID */ public String id; /** * 最大 */ public long max; /** * 最小 */ public long min; /** * 平均 */ public long avg; /** * 処理時間 */ public List<Long> times; /** * コンストラクタ * @param id ID * @param result 結果 * @param times 処理時間 */ public Result ( String id, R result, List<Long> times ) { this.result = result; this.times = times; this.id = id; long sum = 0; max = Long.MIN_VALUE; min = Long.MAX_VALUE; for ( long l : times ) { max = Math.max( max, l ); min = Math.min( min, l ); sum += l; } avg = sum / times.size(); } public String toString () { StringBuilder str = new StringBuilder(); str.append( "---" ).append( id ).append( "\n" ); str.append( avg ).append( ", " ).append( max ).append( ", " ) .append( min ).append( " [ " ); for ( long l : times ) { str.append( l ).append( " " ); } str.append( "]" ); return str.toString(); } } /** * 計測する処理 * * @param <R> 戻り値の型 * */ public static class Task<R> { /** * 処理の実行前に呼び出される * @param i 試行番号 * @throws Exception */ public void before ( int i ) throws Exception {} /** * 処理の実行後に呼び出される * @param i 試行番号 * @throws Exception */ public void after ( int i ) throws Exception {} /** * 計測する処理 * @param i 試行番号 * @return 結果 * @throws Exception */ public R run ( int i ) throws Exception { return null; } } }