1. 説明
Java のマップ トラバーサル方法に関しては、多くの記事で、keySet よりもはるかに効率的であると考えられているentrySet の使用が推奨されています。その理由は、entrySet メソッドはすべてのキーと値のセットを一度に取得するのに対し、keySet はキーごとにもう一度マップ内で値を検索する必要があるためです。全体的な効率。では、実際の状況はどうなっているのでしょうか?
キー + 値の走査、キーの走査、値の走査など、さまざまなシナリオの違いを含め、走査パフォーマンスの実際の違いを理解するために、いくつかの比較テストを実行しようとしました。
2. 比較試験
最初は簡単なテストしか行っていませんでしたが、その結果、keySet の方がパフォーマンスが優れていることがわかり、皆さんは keySet よりも明らかにentrySet の方が優れていると言いました。さらに検証するために、さまざまなテストデータを使用して、より詳細な比較テストを行いました。
2.1 テストデータ
2.1.1 HashMap テストデータ
HashMap-1、サイズは 100 万、キーと値は両方とも文字列、キー値は 1、2、3...1000000 です。
次のようにコードをコピーします。
Map<String, String> マップ = new HashMap<String, String>();
文字列キー、値。
for (i = 1; i <= num; i++) {
キー = "" + i;
値 = "値";
マップ.put(キー, 値);
}
HashMap-2、サイズは 100 万、キーと値は両方とも文字列、キー値は 50、100、150、200、...、50000000 です。
次のようにコードをコピーします。
Map<String, String> マップ = new HashMap<String, String>();
文字列キー、値。
for (i = 1; i <= num; i++) {
キー = "" + (i * 50);
値 = "値";
マップ.put(キー, 値);
}
2.1.2 ツリーマップのテストデータ
TreeMap-1、サイズは 100 万、キーと値は両方とも文字列、キー値は 1、2、3...1000000 です。
次のようにコードをコピーします。
Map<String, String> マップ = new TreeMap<String, String>();
文字列キー、値。
for (i = 1; i <= num; i++) {
キー = "" + i;
値 = "値";
マップ.put(キー, 値);
}
TreeMap-2、サイズは 100 万、キーと値は両方とも文字列、キーの値は 50、100、150、200、...、50000000、より離散的です。
次のようにコードをコピーします。
Map<String, String> マップ = new TreeMap<String, String>();
文字列キー、値。
for (i = 1; i <= num; i++) {
キー = "" + (i * 50);
値 = "値";
マップ.put(キー, 値);
}
2.2 テストシナリオ
keySet、entrySet、values のさまざまな書き込みメソッドを使用して、キー + 値の走査、キーの走査、値の走査の 3 つのシナリオをテストします。
2.2.1 キーと値のトラバース
keySet はキー + 値を走査します (書き方 1):
次のようにコードをコピーします。
Iterator<String> iter = map.keySet().iterator();
while (iter.hasNext()) {
キー = iter.next();
値 = マップ.get(キー);
}
keySet はキー + 値を走査します (書き方 2):
次のようにコードをコピーします。
for (文字列キー:map.keySet()) {
値 = マップ.get(キー);
}
entrySet はキー + 値を走査します (書き込み方法 1):
次のようにコードをコピーします。
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
Entry<String, String> エントリ;
while (iter.hasNext()) {
エントリ = iter.next();
キー = エントリ.getKey();
値 = エントリ.getValue();
}
entrySet はキー + 値を走査します (書き込み方法 2):
次のようにコードをコピーします。
for (Entry<String, String> エントリ:map.entrySet()) {
キー = エントリ.getKey();
値 = エントリ.getValue();
}
2.2.2 トラバースキー
keySet はキーを走査します (書き方 1):
次のようにコードをコピーします。
Iterator<String> iter = map.keySet().iterator();
while (iter.hasNext()) {
キー = iter.next();
}
keySet はキーをトラバースします (書き方 2):
次のようにコードをコピーします。
for (文字列キー:map.keySet()) {
}
entrySet はキーをトラバースします (書き込み方法 1):
次のようにコードをコピーします。
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
キー = iter.next().getKey();
}
entrySet はキーをトラバースします (書き込み方法 2):
次のようにコードをコピーします。
for (Entry<String, String> エントリ:map.entrySet()) {
キー = エントリ.getKey();
}
2.2.3 トラバース値
keySet は値をトラバースします (書き込み方法 1):
次のようにコードをコピーします。
Iterator<String> iter = map.keySet().iterator();
while (iter.hasNext()) {
値 = マップ.get(iter.next());
}
keySet は値をトラバースします (書き込み方法 2):
次のようにコードをコピーします。
for (文字列キー:map.keySet()) {
値 = マップ.get(キー);
}
entrySet は値をトラバースします (書き込み方法 1):
次のようにコードをコピーします。
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
値 = iter.next().getValue();
}
entrySet は値をトラバースします (書き込み方法 2):
次のようにコードをコピーします。
for (Entry<String, String> エントリ:map.entrySet()) {
値 = エントリ.getValue();
}
値が値を横断する (書き方 1):
次のようにコードをコピーします。
Iterator<String> iter = map.values().iterator();
while (iter.hasNext()) {
値 = iter.next();
}
値が値をトラバースする (書き方 2):
次のようにコードをコピーします。
for (文字列値:map.values()) {
}
2.3 試験結果
2.3.1 HashMap のテスト結果
単位:ミリ秒 | ハッシュマップ-1 | ハッシュマップ-2 |
| keySetはキー+値をトラバースします(書き方1) | 39 | 93 |
| keySet はキー + 値をトラバースします (書き方 2) | 38 | 87 |
| entrySet はキー + 値をトラバースします (書き込み方法 1) | 43 | 86 |
| entrySet はキー + 値をトラバースします (書き込み方法 2) | 43 | 85 |
単位:ミリ秒 | ハッシュマップ-1 | ハッシュマップ-2 |
| keySetはキーをトラバースします(書き方1) | 27 | 65 |
| keySetはキーをトラバースします(書き方2) | 26 | 64 |
| エントリセットはキーをトラバースします(書き方1) | 35 | 75 |
| エントリセットはキーをトラバースします(書き方2) | 34 | 74 |
単位:ミリ秒 | ハッシュマップ-1 | ハッシュマップ-2 |
| keySet が value をトラバースする (書き込み方法 1) | 38 | 87 |
| keySet が value をトラバースする (書き込み方法 2) | 37 | 87 |
| エントリセットは値をトラバースします(書き込み方法 1) | 34 | 61 |
| エントリセットは値をトラバースします(書き込み方法 2) | 32 | 62 |
| 値をトラバースする値(書き方1) | 26 | 48 |
| 値をトラバースする値(書き方2) | 26 | 48 |
2.3.2 ツリーマップのテスト結果
単位:ミリ秒 | ツリーマップ-1 | ツリーマップ-2 |
| keySetはキー+値をトラバースします(書き方1) | 430 | 451 |
| keySet はキー + 値をトラバースします (書き方 2) | 429 | 450 |
| entrySet はキー + 値をトラバースします (書き込み方法 1) | 77 | 84 |
| entrySet はキー + 値をトラバースします (書き込み方法 2) | 70 | 68 |
単位:ミリ秒 | ツリーマップ-1 | ツリーマップ-2 |
| keySetはキーをトラバースします(書き方1) | 50 | 49 |
| keySetはキーをトラバースします(書き方2) | 49 | 48 |
| エントリセットはキーをトラバースします(書き方1) | 66 | 64 |
| エントリセットはキーをトラバースします(書き方2) | 65 | 63 |
単位:ミリ秒 | ツリーマップ-1 | ツリーマップ-2 |
| keySet が value をトラバースする (書き込み方法 1) | 432 | 448 |
| keySet が value をトラバースする (書き込み方法 2) | 430 | 448 |
| エントリセットは値をトラバースします(書き込み方法 1) | 62 | 61 |
| エントリセットは値をトラバースします(書き込み方法 2) | 62 | 61 |
| 値をトラバースする値(書き方1) | 46 | 46 |
| 値をトラバースする値(書き方2) | 45 | 46 |
3. 結論
3.1 HashMapを使用する場合
1. キーと値を同時に走査する場合、keySet メソッドとentrySet メソッドのパフォーマンスの違いは、複雑さ (複雑なオブジェクト)、離散性、競合率などのキーの特定の条件によって異なります。言い換えれば、HashMap で値を検索するコストに依存します。すべてのキーと値を一度に取得するentrySetの操作にはパフォーマンスのオーバーヘッドがあり、この損失が値を検索するHashMapのオーバーヘッドよりも小さい場合、entrySetのパフォーマンスの利点が反映されます。たとえば、上記の比較テストでは、キーが最も単純な数値文字列の場合、keySet の方が効率的であり、entrySet よりも時間が 10% 短くなります。一般的には、entrySet を使用することをお勧めします。キーが非常に単純な場合、そのパフォーマンスは keySet よりわずかに劣る可能性がありますが、キーが複雑になるにつれて、entrySet の利点が明確に反映されます。もちろん、実際の状況に応じて選択できます
2. キーのみをトラバースする場合は、keySet メソッドの方が適切です。これは、entrySet は無駄な値も削除するため、パフォーマンスとスペースが無駄になるためです。上記のテスト結果では、keySet は、entrySet メソッドよりも 23% 時間がかかりません。
3. 値のみをトラバースする場合は、vlaues メソッドを使用するのが最良の選択ですが、entrySet は keySet メソッドよりわずかに優れています。
4. さまざまなトラバーサル記述方法の中で、若干効率的な次の記述方法を使用することをお勧めします。
次のようにコードをコピーします。
for (文字列キー:map.keySet()) {
値 = マップ.get(キー);
}
for (Entry<String, String> エントリ:map.entrySet()) {
キー = エントリ.getKey();
値 = エントリ.getValue();
}
for (文字列値:map.values()) {
}
3.2 ツリーマップを使用する場合
1. キーと値を同時に走査する場合、HashMap とは異なり、entrySet のパフォーマンスは keySet のパフォーマンスよりもはるかに高くなります。これは TreeMap のクエリ効率によって決まります。つまり、TreeMap で値を検索するコストは比較的大きく、entrySet からすべてのキーと値を一度に取得するコストよりも大幅に高くなります。したがって、TreeMap を移動するときは、entrySet メソッドを使用することを強くお勧めします。
2. キーのみをトラバースする場合は、keySet メソッドの方が適切です。これは、entrySet は無駄な値も削除するため、パフォーマンスとスペースが無駄になるためです。上記のテスト結果では、keySet は、entrySet メソッドよりも 24% 時間がかかりません。
3. 値のみをトラバースする場合は、vlaues メソッドを使用するのが最良の選択であり、entrySet の方が keySet メソッドよりも明らかに優れています。
4. さまざまなトラバーサル記述方法の中で、若干効率的な次の記述方法を使用することをお勧めします。
次のようにコードをコピーします。
for (文字列キー:map.keySet()) {
値 = マップ.get(キー);
}
for (Entry<String, String> エントリ:map.entrySet()) {
キー = エントリ.getKey();
値 = エントリ.getValue();
}
for (文字列値:map.values()) {
}