1. Penjelasan
Mengenai metode Map traversal di Java, banyak artikel yang merekomendasikan penggunaan entrySet, yang dianggap jauh lebih efisien daripada keySet. Alasannya adalah: metode entrySet mendapatkan kumpulan semua kunci dan nilai sekaligus; sedangkan keySet hanya mendapatkan kumpulan kunci, untuk setiap kunci, nilainya harus dicari di Peta sekali lagi, sehingga mengurangi efisiensi keseluruhan. Jadi bagaimana situasi sebenarnya?
Untuk memahami kesenjangan nyata dalam kinerja traversal, termasuk perbedaan dalam skenario yang berbeda seperti traversing key+value, traversing key, traversing value, dll., saya mencoba melakukan beberapa uji komparatif.
2. Pengujian komparatif
Pada awalnya, hanya tes sederhana yang dilakukan, tetapi hasilnya menunjukkan bahwa kinerja keySet lebih baik, yang membuat saya bingung. Bukankah mereka semua mengatakan bahwa entrySet jelas lebih baik daripada keySet? Untuk memverifikasi lebih lanjut, data uji yang berbeda digunakan untuk pengujian komparatif yang lebih rinci.
2.1 Uji data
2.1.1 data uji HashMap
HashMap-1, ukurannya 1 juta, kunci dan nilainya sama-sama String, nilai kuncinya 1, 2, 3...1000000:
Copy kode kodenya sebagai berikut:
Peta<String, String> peta = HashMap baru<String, String>();
Kunci string, nilai;
untuk (i = 1; i <= angka; i++) {
kunci = "" + saya;
nilai = "nilai";
map.put(kunci, nilai);
}
HashMap-2, ukurannya 1 juta, kunci dan nilainya sama-sama String, nilai kuncinya 50, 100, 150, 200,..., 50000000:
Copy kode kodenya sebagai berikut:
Peta<String, String> peta = HashMap baru<String, String>();
Kunci string, nilai;
untuk (i = 1; i <= angka; i++) {
kunci = "" + (i * 50);
nilai = "nilai";
map.put(kunci, nilai);
}
2.1.2 Data uji TreeMap
TreeMap-1, ukurannya 1 juta, kunci dan nilainya sama-sama String, nilai kuncinya 1, 2, 3...1000000:
Copy kode kodenya sebagai berikut:
Peta<String, String> peta = Peta Pohon baru<String, String>();
Kunci string, nilai;
untuk (i = 1; i <= angka; i++) {
kunci = "" + saya;
nilai = "nilai";
map.put(kunci, nilai);
}
TreeMap-2, ukurannya 1 juta, kunci dan nilainya sama-sama String, nilai kuncinya 50, 100, 150, 200,..., 50000000, lebih diskrit:
Copy kode kodenya sebagai berikut:
Peta<String, String> peta = Peta Pohon baru<String, String>();
Kunci string, nilai;
untuk (i = 1; i <= angka; i++) {
kunci = "" + (i * 50);
nilai = "nilai";
map.put(kunci, nilai);
}
2.2 Skenario pengujian
Gunakan berbagai metode penulisan keySet, entrySet, dan nilai untuk menguji tiga skenario: traversing key+value, traversing key, dan traversing value.
2.2.1 Melintasi kunci+nilai
keySet melintasi kunci+nilai (metode penulisan 1):
Copy kode kodenya sebagai berikut:
Iterator<String> iter = peta.keySet().iterator();
while (iter.hasNext()) {
kunci = iter.next();
nilai = peta.get(kunci);
}
keySet melintasi kunci+nilai (metode penulisan 2):
Copy kode kodenya sebagai berikut:
untuk (Kunci string : map.keySet()) {
nilai = peta.get(kunci);
}
entrySet melintasi kunci+nilai (metode penulisan 1):
Copy kode kodenya sebagai berikut:
Iterator<Entri<String, String>> iter = peta.entrySet().iterator();
entri<String, String> entri;
while (iter.hasNext()) {
entri = iter.next();
kunci = entri.getKey();
nilai = entri.getValue();
}
entrySet melintasi kunci+nilai (metode penulisan 2):
Copy kode kodenya sebagai berikut:
for (Entri<String, String> entri: map.entrySet()) {
kunci = entri.getKey();
nilai = entri.getValue();
}
2.2.2 Kunci lintasan
keySet melintasi kunci (metode penulisan 1):
Copy kode kodenya sebagai berikut:
Iterator<String> iter = peta.keySet().iterator();
while (iter.hasNext()) {
kunci = iter.next();
}
keySet melintasi kunci (metode penulisan 2):
Copy kode kodenya sebagai berikut:
untuk (Kunci string : map.keySet()) {
}
entrySet melintasi kunci (metode penulisan 1):
Copy kode kodenya sebagai berikut:
Iterator<Entri<String, String>> iter = peta.entrySet().iterator();
while (iter.hasNext()) {
kunci = iter.next().getKey();
}
entrySet melintasi kunci (metode penulisan 2):
Copy kode kodenya sebagai berikut:
for (Entri<String, String> entri: map.entrySet()) {
kunci = entri.getKey();
}
2.2.3 Nilai lintasan
keySet melintasi nilai (metode penulisan 1):
Copy kode kodenya sebagai berikut:
Iterator<String> iter = peta.keySet().iterator();
while (iter.hasNext()) {
nilai = peta.get(iter.next());
}
keySet melintasi nilai (metode penulisan 2):
Copy kode kodenya sebagai berikut:
untuk (Kunci string : map.keySet()) {
nilai = peta.get(kunci);
}
entrySet melintasi nilai (metode penulisan 1):
Copy kode kodenya sebagai berikut:
Iterator<Entri<String, String>> iter = peta.entrySet().iterator();
while (iter.hasNext()) {
nilai = iter.next().getValue();
}
entrySet melintasi nilai (metode penulisan 2):
Copy kode kodenya sebagai berikut:
for (Entri<String, String> entri: map.entrySet()) {
nilai = entri.getValue();
}
nilai melintasi nilai (metode penulisan 1):
Copy kode kodenya sebagai berikut:
Iterator<String> iter = peta.nilai().iterator();
while (iter.hasNext()) {
nilai = iter.next();
}
nilai melintasi nilai (metode penulisan 2):
Copy kode kodenya sebagai berikut:
for (Nilai string : peta.nilai()) {
}
2.3 Hasil tes
2.3.1 Hasil pengujian HashMap
Satuan: milidetik | HashMap-1 | HashMap-2 |
| keySet melintasi kunci+nilai (metode penulisan 1) | 39 | 93 |
| keySet melintasi kunci+nilai (metode penulisan 2) | 38 | 87 |
| entrySet melintasi kunci+nilai (metode penulisan 1) | 43 | 86 |
| entrySet melintasi kunci+nilai (metode penulisan 2) | 43 | 85 |
Satuan: milidetik | HashMap-1 | HashMap-2 |
| keySet melintasi kunci (metode penulisan 1) | 27 | 65 |
| keySet melintasi kunci (metode penulisan 2) | 26 | 64 |
| entrySet melintasi kunci (metode penulisan 1) | 35 | 75 |
| entrySet melintasi kunci (metode penulisan 2) | 34 | 74 |
Satuan: milidetik | HashMap-1 | HashMap-2 |
| keySet melintasi nilai (metode penulisan 1) | 38 | 87 |
| keySet melintasi nilai (metode penulisan 2) | 37 | 87 |
| entrySet melintasi nilai (metode penulisan 1) | 34 | 61 |
| entrySet melintasi nilai (metode penulisan 2) | 32 | 62 |
| nilai melintasi nilai (metode penulisan 1) | 26 | 48 |
| nilai melintasi nilai (metode penulisan 2) | 26 | 48 |
2.3.2 Hasil pengujian TreeMap
Satuan: milidetik | Peta Pohon-1 | Peta Pohon-2 |
| keySet melintasi kunci+nilai (metode penulisan 1) | 430 | 451 |
| keySet melintasi kunci+nilai (metode penulisan 2) | 429 | 450 |
| entrySet melintasi kunci+nilai (metode penulisan 1) | 77 | 84 |
| entrySet melintasi kunci+nilai (metode penulisan 2) | 70 | 68 |
Satuan: milidetik | Peta Pohon-1 | Peta Pohon-2 |
| keySet melintasi kunci (metode penulisan 1) | 50 | 49 |
| keySet melintasi kunci (metode penulisan 2) | 49 | 48 |
| entrySet melintasi kunci (metode penulisan 1) | 66 | 64 |
| entrySet melintasi kunci (metode penulisan 2) | 65 | 63 |
Satuan: milidetik | Peta Pohon-1 | Peta Pohon-2 |
| keySet melintasi nilai (metode penulisan 1) | 432 | 448 |
| keySet melintasi nilai (metode penulisan 2) | 430 | 448 |
| entrySet melintasi nilai (metode penulisan 1) | 62 | 61 |
| entrySet melintasi nilai (metode penulisan 2) | 62 | 61 |
| nilai melintasi nilai (metode penulisan 1) | 46 | 46 |
| nilai melintasi nilai (metode penulisan 2) | 45 | 46 |
3. Kesimpulan
3.1 Jika Anda menggunakan HashMap
1. Saat melintasi kunci dan nilai secara bersamaan, perbedaan kinerja antara metode keySet dan entrySet bergantung pada kondisi spesifik kunci, seperti kompleksitas (objek kompleks), keleluasaan, tingkat konflik, dll. Dengan kata lain, ini bergantung pada biaya pencarian nilai di HashMap. Pengoperasian entrySet untuk mengambil semua kunci dan nilai sekaligus memiliki overhead kinerja. Ketika kerugian ini lebih kecil dari overhead HashMap yang mencari nilai, keunggulan kinerja entrySet akan tercermin. Misalnya, dalam pengujian perbandingan di atas, jika kuncinya adalah string numerik yang paling sederhana, keySet mungkin lebih efisien, membutuhkan waktu 10% lebih sedikit daripada entrySet. Secara umum, disarankan untuk menggunakan entrySet. Karena ketika kuncinya sangat sederhana, kinerjanya mungkin sedikit lebih rendah daripada keySet, namun dapat dikontrol ketika kuncinya menjadi lebih rumit, keunggulan entrySet akan terlihat jelas. Tentu saja kita bisa memilih sesuai dengan keadaan sebenarnya
2. Ketika hanya melintasi kunci, metode keySet lebih tepat, karena entrySet juga mengeluarkan nilai-nilai yang tidak berguna, sehingga membuang-buang kinerja dan ruang. Pada hasil pengujian di atas, keySet membutuhkan waktu 23% lebih sedikit dibandingkan metode entrySet.
3. Ketika hanya melintasi nilai, menggunakan metode vlaues adalah pilihan terbaik, entrySet sedikit lebih baik daripada metode keySet.
4. Di antara berbagai metode penulisan traversal, disarankan untuk menggunakan metode penulisan berikut, yang sedikit lebih efisien:
Copy kode kodenya sebagai berikut:
untuk (Kunci string : map.keySet()) {
nilai = peta.get(kunci);
}
for (Entri<String, String> entri: map.entrySet()) {
kunci = entri.getKey();
nilai = entri.getValue();
}
for (Nilai string : peta.nilai()) {
}
3.2 Jika Anda menggunakan TreeMap
1. Saat melintasi kunci dan nilai secara bersamaan, tidak seperti HashMap, kinerja entrySet jauh lebih tinggi daripada keySet. Hal ini ditentukan oleh efisiensi kueri TreeMap. Dengan kata lain, biaya pencarian nilai di TreeMap relatif besar, jauh lebih tinggi daripada biaya pengambilan semua kunci dan nilai sekaligus dari entrySet. Oleh karena itu, sangat disarankan untuk menggunakan metode entrySet saat melintasi TreeMap.
2. Ketika hanya melintasi kunci, metode keySet lebih tepat, karena entrySet juga mengeluarkan nilai-nilai yang tidak berguna, sehingga membuang-buang kinerja dan ruang. Pada hasil pengujian di atas, keySet membutuhkan waktu 24% lebih sedikit dibandingkan metode entrySet.
3. Ketika hanya melintasi nilai, menggunakan metode vlaues adalah pilihan terbaik, dan entrySet juga jelas lebih baik daripada metode keySet.
4. Di antara berbagai metode penulisan traversal, disarankan untuk menggunakan metode penulisan berikut, yang sedikit lebih efisien:
Copy kode kodenya sebagai berikut:
untuk (Kunci string : map.keySet()) {
nilai = peta.get(kunci);
}
for (Entri<String, String> entri: map.entrySet()) {
kunci = entri.getKey();
nilai = entri.getValue();
}
for (Nilai string : peta.nilai()) {
}