How many traversal methods does HashMap have? Which is recommended?

This article has included the interview selection series, Gitee open source address: gitee.com/mydb/interv...

There are many HashMap traversal methods, and different JDK versions have different writing methods. JDK 8 provides three HashMap traversal methods, which breaks the embarrassment that the previous traversal methods are "very bloated".

1. Traversal before JDK 8

Before JDK 8, EntrySet and KeySet were mainly used for traversal. The specific implementation code is as follows.

1.1 EntrySet traversal

EntrySet is the main method of HashMap traversal in the early stage. Its implementation code is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    // Loop traversal
    for (Map.Entry<String, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }
}
Copy code

The execution results of the above procedures are shown in the figure below:

1.2 KeySet traversal

The traversal method of KeySet is to cycle the Key content, and then obtain the Value through map.get(key). The specific implementation is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    // Loop traversal
    for (String key : map.keySet()) {
        System.out.println(key + ":" + map.get(key));
    }
}
Copy code

The execution results of the above procedures are shown in the figure below:

KeySet performance issues

From the above code, we can see that the performance of traversing with KeySet is not as good as that of EntrySet, because KeySet actually cycles through the set twice. The first cycle is to cycle the Key, and it is necessary to use map.get(key) to obtain Value, which is equivalent to cycling through the set. Therefore, KeySet cycle cannot be recommended because it cycles twice, which is inefficient.

1.3 EntrySet iterator traversal

In addition to the above direct loops, EntrySet and KeySet can also use their iterators for loops. For example, the iterator implementation code of EntrySet is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    // Loop traversal
    Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, String> entry = iterator.next();
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }
}
Copy code

The execution results of the above procedures are shown in the figure below:

1.4 KeySet iterator traversal

KeySet can also be traversed by iterators. The implementation code is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    // Loop traversal
    Iterator<String> iterator = map.keySet().iterator();
    while (iterator.hasNext()) {
        String key = iterator.next();
        System.out.println(key + ":" + map.get(key));
    }
}
Copy code

The execution results of the above procedures are shown in the figure below:

Although the KeySet loop method is not recommended, it is still necessary to understand it.

1.5 role of iterators

Since you can traverse directly, why use an iterator? We will know from the following example.

Delete without iterator

If we do not use iterators, if we delete elements in the traversal code when traversing the EntrySet, the implementation of the code is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    // Loop traversal
    for (Map.Entry<String, String> entry : map.entrySet()) {
        if ("Java".equals(entry.getKey())) {
            // Delete this item
            map.remove(entry.getKey());
            continue;
        }
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }
}
Copy code

The execution results of the above procedures are shown in the figure below:

You can see that if you dynamically delete elements in the traversal code, the non iterator method will report an error.

Delete using iterator

Next, we use the iterator to loop the EntrySet and dynamically delete the elements in the loop. The implementation code is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    // Loop traversal
    Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, String> entry = iterator.next();
        if ("Java".equals(entry.getKey())) {
            // Delete this item
            iterator.remove();
            continue;
        }
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }
}
Copy code

The execution results of the above procedures are shown in the figure below:

From the above results, we can see that the advantage of using iterators is that the elements in the collection can be deleted dynamically during the loop. The above non iterator method cannot delete elements during the loop (the program will report an error).

2. Traversal after JDK 8

After JDK 8, the traversal of HashMap becomes much more convenient. JDK 8 includes the following three traversal methods:

  • Traversal using Lambda
  • Single threaded traversal using Stream
  • Traversal using Stream multithreading

Let's look at it separately.

2.1 Lambda traversal

The implementation code using the traversal method of Lambda expression is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    
    // Loop traversal
    map.forEach((key, value) -> {
        System.out.println(key + ":" + value);
    });
}
Copy code

The execution results of the above procedures are shown in the figure below:

2.2 Stream single thread traversal

Stream traversal is to get the EntrySet of the map set first, and then execute the forEach loop. The implementation code is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    
    // Loop traversal
    map.entrySet().stream().forEach((entry) -> {
        System.out.println(entry.getKey() + ":" + entry.getValue());
    });
}
Copy code

The execution results of the above procedures are shown in the figure below:

2.3 multi thread traversal of stream

The traversal mode of Stream multithreading is similar to the previous traversal mode, except that a parallel concurrent execution method is executed. This method will generate the corresponding number of threads according to the current hardware configuration, and then perform the traversal operation. The implementation code is as follows:

public static void main(String[] args) {
    // Create and assign hashmap
    HashMap<String, String> map = new HashMap() {{
        put("Java", " Java Value.");
        put("MySQL", " MySQL Value.");
        put("Redis", " Redis Value.");
    }};
    // Loop traversal
    map.entrySet().stream().parallel().forEach((entry) -> {
        System.out.println(entry.getKey() + ":" + entry.getValue());
    });
}
Copy code

The execution results of the above procedures are shown in the figure below:

Note the execution results of the above pictures. It can be seen that the current execution results are different from all previous traversal results (the order of printing elements is different). Because the program is executed concurrently, there is no way to ensure the execution order and printing order of elements, which is the characteristic of parallel programming.

Which traversal method is recommended?

The recommended traversal methods for different scenarios are different. For example, if it is a development environment after JDK 8, the Stream traversal method is recommended because it is concise enough; If you need to dynamically delete elements during traversal, it is recommended to use iterator traversal; If you care about the execution efficiency of the program when traversing, it is recommended to use Stream multithreading traversal because it is fast enough. Therefore, the answer to this question is not fixed. We need to know the advantages and disadvantages of each traversal method, and then work flexibly according to different scenarios.

summary

This paper introduces seven HashMap traversal methods. Before JDK 8, the traversal methods of EntrySet and KeySet are mainly used, while the traversal method of KeySet has low performance and is generally not recommended. However, after JDK 8, there are new options for traversal. You can use relatively simple Lambda traversal or Stream multi-threaded traversal with high performance. ​

Right and wrong are judged by ourselves, bad reputation is heard by others, and the number of gains and losses is safe.



Link: https://juejin.cn/post/7039197348391551013
 

Keywords: Java Back-end Interview Programmer

Added by will on Thu, 09 Dec 2021 01:48:22 +0200