1. Elaboration
For the way in which map is traversed in Java, many articles recommend using EntrySet, which is more efficient than keyset. The reason is: The EntrySet method gets all the keys and value at once, and keyset gets only the set of keys, and for each key, it goes to the map to find the value in extra time, thus reducing the overall efficiency. So what's the real story?
To understand the real difference in traversal performance, including the differences in traversing key+value, traversing keys, traversing the value, and so on, I tried some contrast tests.
2. Contrast Test
Initially only a simple test, but the results show that keyset performance is better, this makes me very puzzling, not all said EntrySet significantly better than keyset? For further verification, different test data were used for more detailed comparison testing.
2.1 test Data
2.1.1 HashMap test Data
- HashMap-1, size 1 million, key and value are String,key values of 1, 2, 3 ... 1000000:
map<string, string> map = new hashmap<string, string> (); String key, value; for (i = 1; I <= num; i++) { Key = "" + I; Value = "value"; Map.put (key, value); } |
- HashMap-2, size 1 million, key and value are string,key values of 50, 100, 150, 、......、 50000000:
map<string, string> map = new hashmap<string, string> (); String key, value; for (i = 1; I <= num; i++) { Key = "" + (I * 50); Value = "value"; Map.put (key, value); } |
2.1.2 TreeMap test Data
- TreeMap-1, size 1 million, key and value are String,key values of 1, 2, 3 ... 1000000:
map<string, string> map = new treemap<string, string> (); String key, value; for (i = 1; I <= num; i++) { Key = "" + I; Value = "value"; Map.put (key, value); } |
- TreeMap-2, size 1 million, key and value are string,key values of 50, 100, 150, 、......、 50000000, and more discrete:
map<string, string> map = new treemap<string, string> (); String key, value; for (i = 1; I <= num; i++) { Key = "" + (I * 50); Value = "value"; Map.put (key, value); } |
2.2 Test scenarios
Test three scenarios using keyset, EntrySet, and values in a variety of ways: traversing Key+value, traversing key, and traversing the value's scene.
2.2.1 Traversal Key+value
- Keyset traversal Key+value (notation 1):
Iterator<string> iter = Map.keyset (). Iterator (); while (Iter.hasnext ()) { Key = Iter.next (); Value = Map.get (key); } |
- Keyset traversal Key+value (notation 2):
For (String Key:map.keySet ()) { Value = Map.get (key); } |
- EntrySet Traversal Key+value (notation 1):
Iterator<entry<string, string>> iter = Map.entryset (). Iterator (); Entry<string, string> Entry; while (Iter.hasnext ()) { Entry = Iter.next (); Key = Entry.getkey (); Value = Entry.getvalue (); } |
- EntrySet Traversal Key+value (notation 2):
For (entry<string, string> entry:map.entrySet ()) { Key = Entry.getkey (); Value = Entry.getvalue (); } |
2.2.2 Traversal key
- Keyset traversal key (notation 1):
Iterator<string> iter = Map.keyset (). Iterator (); while (Iter.hasnext ()) { Key = Iter.next (); } |
- Keyset traversal key (notation 2):
For (String Key:map.keySet ()) { } |
- EntrySet traversal key (notation 1):
Iterator<entry<string, string>> iter = Map.entryset (). Iterator (); while (Iter.hasnext ()) { Key = Iter.next (). GetKey (); } |
- EntrySet traversal key (notation 2):
For (entry<string, string> entry:map.entrySet ()) { Key = Entry.getkey (); } |
2.2.3 Traversal value
- Keyset traversal value (notation 1):
Iterator<string> iter = Map.keyset (). Iterator (); while (Iter.hasnext ()) { Value = Map.get (Iter.next ()); } |
- Keyset traversal value (notation 2):
For (String Key:map.keySet ()) { Value = Map.get (key); } |
- EntrySet Traversal value (notation 1):
Iterator<entry<string, string>> iter = Map.entryset (). Iterator (); while (Iter.hasnext ()) { Value = Iter.next (). GetValue (); } |
- EntrySet Traversal value (notation 2):
For (entry<string, string> entry:map.entrySet ()) { Value = Entry.getvalue (); } |
- Values traverse value (1):
Iterator<string> iter = Map.values (). Iterator (); while (Iter.hasnext ()) { Value = Iter.next (); } |
- Values traverse value (2):
For (String value:map.values ()) { } |
2.3 Test Results
2.3.1 HashMap Test Results
Units: Milliseconds |
HashMap-1 |
HashMap-2 |
Keyset traversal Key+value (notation 1) |
39 |
93 |
Keyset traversal Key+value (notation 2) |
38 |
87 |
EntrySet Traversal Key+value (notation 1) |
43 |
86 |
EntrySet Traversal Key+value (notation 2) |
43 |
85 |
Units: Milliseconds |
HashMap-1 |
HashMap-2 |
Keyset traversal key (notation 1) |
27 |
65 |
Keyset traversal key (notation 2) |
26 |
64 |
EntrySet traversal key (notation 1) |
35 |
75 |
EntrySet traversal key (notation 2) |
34 |
74 |
Units: Milliseconds |
HashMap-1 |
HashMap-2 |
Keyset traversal value (notation 1) |
38 |
87 |
Keyset traversal value (notation 2) |
37 |
87 |
EntrySet Traversal value (notation 1) |
34 |
61 |
EntrySet Traversal value (notation 2) |
32 |
62 |
Values traverse value (notation 1) |
26 |
48 |
Values traverse value (notation 2) |
26 |
48 |
2.3.2 TreeMap Test Results
Units: Milliseconds |
TreeMap-1 |
TreeMap-2 |
Keyset traversal Key+value (notation 1) |
430 |
451 |
Keyset traversal Key+value (notation 2) |
429 |
450 |
EntrySet Traversal Key+value (notation 1) |
77 |
84 |
EntrySet Traversal Key+value (notation 2) |
70 |
68 |
Units: Milliseconds |
TreeMap-1 |
TreeMap-2 |
Keyset traversal key (notation 1) |
50 |
49 |
Keyset traversal key (notation 2) |
49 |
48 |
EntrySet traversal key (notation 1) |
66 |
64 |
EntrySet traversal key (notation 2) |
65 |
63 |
Units: Milliseconds |
TreeMap-1 |
TreeMap-2 |
Keyset traversal value (notation 1) |
432 |
448 |
Keyset traversal value (notation 2) |
430 |
448 |
EntrySet Traversal value (notation 1) |
62 |
61 |
EntrySet Traversal value (notation 2) |
62 |
61 |
Values traverse value (notation 1) |
46 |
46 |
Values traverse value (notation 2) |
45 |
46 |
3. Conclusion
3.1 If you use HashMap
- When traversing key and value simultaneously, the performance difference between the keyset and the EntrySet method depends on the specifics of the key, such as complexity (complex object), dispersion, conflict rate, and so on. In other words, it depends on the cost of HashMap finding value. EntrySet the performance cost of removing all keys and value at once, when the loss is less than the cost of HashMap to find value, the EntrySet is shown. For example, when key is the simplest numeric string in the comparison test above, keyset may be more efficient and time consuming is 10% less than EntrySet. EntrySet is recommended for use in general. Because when key is very simple, its performance may be slightly lower than keyset, but it is controllable, and with the complexity of key, the advantages of entryset will be clearly reflected. Of course, we can choose according to the actual situation
- The keyset method is more appropriate when traversing key only, because EntrySet takes out useless value and wastes performance and space. In the above test results, keyset is 23% less time consuming than the EntrySet method.
- Using the Vlaues method is the best choice when traversing only value, and entryset is slightly better than the keyset method.
- In different traversal notation, it is recommended to use the following wording, which is slightly more efficient:
For (String Key:map.keySet ()) { Value = Map.get (key); } |
For (entry<string, string> entry:map.entrySet ()) { Key = Entry.getkey (); Value = Entry.getvalue (); } |
For (String value:map.values ()) { } |
3.2 If you use TreeMap
- When traversing key and value at the same time, unlike HashMap, entryset performance is much higher than keyset. This is determined by the query efficiency of TREEMAP, that is, the overhead of treemap finding value is significantly higher than the cost of entryset to take out all keys and value at once. Therefore, it is strongly recommended to use the EntrySet method when traversing TreeMap.
- The keyset method is more appropriate when traversing key only, because EntrySet takes out useless value and wastes performance and space. In the above test results, keyset is 24% less time consuming than the EntrySet method.
- Using the Vlaues method is the best choice when traversing only value, and entryset is significantly better than the keyset method.
- In different traversal notation, it is recommended to use the following wording, which is slightly more efficient:
For (String Key:map.keySet ()) { Value = Map.get (key); } |
For (entry<string, string> entry:map.entrySet ()) { Key = Entry.getkey (); Value = Entry.getvalue (); } |
For (String value:map.values ()) { } |
Performance comparison of various traversal modes of Java map