CSVファイルのデータ取り込みや大量データを扱う処理において、ArrayListとMapどちらを使うべきか?
普段はArrayListにDTOオブジェクトを格納し、必要な時にListを回して欲しいDTOを取得することがほとんどですが、やはりデータ量が増えるにつれて処理効率が落ちているっぽいので、この際はっきりさせようと調査しました。
1. 結論
早速結論ですが、DTOをArrayListとMapにそれぞれ格納した場合、該当のDTOを取得するにはMapの方が処理効率は良い(早い)です。
ただ、何でもかんでもMapを使えば良いという話ではないので、その辺り含め確認していきます。
2. 検証準備
今回の検証は以下の流れで実施します。
1. UserDtoのオブジェクトを用意し、ArrayListに10万件を格納
2. userIdを検索キーにしてUserDtoを取得
3. 「1件目」「50万件目」「100万件目」に格納されているDTOを取得して時間を計測
4. 計測は3回実施する(JVMの処理の平均をとる)
5. MapはArrayListの100万件をMapに格納してからDTOを取得する
5について、本来は直接Mapに格納すべきですが、現場の諸事情によりArrayList→Map格納の手順にしています。
UsetDtoはこちら。
10万件のArrayListは下記処理で作成。
userIdには1から100万までインクリメントしながら格納します。
3. 検証
3-1. ArrayList
処理時間は「検索開始前」「userIdでDTOを取得した後」で計測します。
1回目。
2回目。
3回目。
ArrayListは格納順にループを回していくので、リストに格納されるデータが増えて順番も後ろになると検索に少し時間がかかる。
※30msなんで1秒にも満たないけど、何回も検索したりDTOに格納するデータサイズによっては処理効率に影響でそう
3-2. Map
ArrayListと同じく、処理時間は「検索開始前」「userIdでDTOを取得した後」で計測します。
また、Map格納時のキーはuserIdで値にuserDtoを格納しています。
1回目。
2回目。
3回目。
ArrayListをMapに格納するのに少し時間がかかってます。
が、DTO取得は0msとミリ秒では計測できないくらい一瞬でした。
4. 検証結果
1件目 | 50万件目 | 100万件目 | |
---|---|---|---|
ArrayList | 0ms | 21ms | 29ms |
Map | 0ms | 0ms | 0ms |
値は平均値で出していますが、こう見るとMapはハッシュテーブルによる検索なので格納順に関わらず即取得できています。
5. ArrayListとMapの使い分け
表を見るとMap使えばいいじゃん、となりますが、ArrayListを使うメリットもあります。
例えば、userIdではなくてloginId等の任意の変数の値でDTOを取得したい場合。
Mapだとkey値での検索になるので、任意の値でのDTO取得は厳しいです。
また、keyには同じ値を設定できないので「名前の苗字が山田の人達を抽出して」というような複数ヒットするDTOを取得することも厳しいです。
なので、使い分け的には以下の感じになるかと。
・キーが一意で高速に値を取得したい=Map
・キー以外の値での検索や順番に値を取得したい=ArrayList
キー値で何度も検索する時はMapにして、順番を意識したりそこまで格納するデータがないときはArrayListを使おうかな。