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

There are a number of HashMap traversal methods. JDK 8 provides three HashMap traversal methods to overcome the embarrassment of “bloated” traversal methods.

1. Traversal before JDK 8

Prior to JDK 8, EntrySet and KeySet were used for traversal. The implementation code is as follows.

1.1 EntrySet traversal

EntrySet was the primary method of HashMap traversal in the early days, and its implementation code is as follows:

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

The execution result of the above program is shown in the figure below:

1.2 KeySet traversal

Map. get(Key) to obtain the Value of a KeySet, as follows:

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

The execution result of the above program is shown in the figure below:

KeySet performance problem

KeySet iterates through the set twice. The first iterates through the Key, and the second iterates through the set using map.get(Key). So the KeySet loop is not recommended because it is inefficient to loop twice.

1.3 EntrySet iterator traversal

EntrySet and KeySet iterators can also be used to loop through EntrySet iterators.

public static void main(String[] args) {
    // Create and assign a hashMap
    HashMap<String, String> map = new HashMap() {{
        put("Java"." Java Value.");
        put("MySQL"." MySQL Value.");
        put("Redis"." Redis Value.");
    }};
    // loop over
    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 the code

The execution result of the above program is shown in the figure below:

1.4 KeySet iterator traversal

The KeySet can also be iterated through using iterators as follows:

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

The execution result of the above program is shown in the figure below:KeySet loops are not recommended, but they are worth knowing.

1.5 The role of iterators

Why use iterators when you can iterate directly? We can see this through the following example.

Delete without iterator

Without iterators, if we were to delete elements in the traversal code while iterating through EntrySet, the code would look like this:

public static void main(String[] args) {
    // Create and assign a hashMap
    HashMap<String, String> map = new HashMap() {{
        put("Java"." Java Value.");
        put("MySQL"." MySQL Value.");
        put("Redis"." Redis Value.");
    }};
    // loop over
    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 the code

The execution result of the above program is shown in the figure below:As you can see, the non-iterator approach is an error if the element is dynamically deleted in the iterated code.

Delete using iterators

Next, we use an iterator to loop through EntrySet and dynamically delete elements in the loop as follows:

public static void main(String[] args) {
    // Create and assign a hashMap
    HashMap<String, String> map = new HashMap() {{
        put("Java"." Java Value.");
        put("MySQL"." MySQL Value.");
        put("Redis"." Redis Value.");
    }};
    // loop over
    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 the code

The execution result of the above program is shown in the figure below:As can be seen from the above results,The advantage of using iterators is that you can dynamically delete elements from a collection as you loop through it. The above non-iterator method cannot delete elements during the loop (the program will report an error).

2. Traversal after JDK 8

HashMap traversal became much easier in JDK 8, which included the following three traversal methods:

  • Lambda traversal is used
  • Stream single-threaded traversal
  • Multithreaded traversal using Stream

Let’s look at them separately.

2.1 Lambda traversal

Lambda expression traversal method implementation code is as follows:

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

The execution result of the above program is shown in the figure below:

2.2 Stream Single-thread traversal

Stream traversal is an EntrySet of a map, and then a forEach loop.

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

The execution result of the above program is shown in the figure below:

2.3 Stream Multi-threaded traversal

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

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

The execution result of the above program is shown in the figure below:Notice the result of the above image, you can see that the current execution result is different from all the previous traversal results (print elements in different order), because the program is executed concurrently, there is no way to guarantee the execution order of elements and print order, which is the characteristic of concurrent programming.

Which traversal method is recommended?

The recommended traversal method varies from scenario to scenario. For example, in a development environment after JDK 8, Stream traversal is recommended because it is concise enough. If you need to dynamically delete elements during traversal, iterator traversal is recommended. If you are concerned about the efficiency of the program when traversing, then it is recommended to use the Stream multithreaded traversal mode, because it is fast enough. So the answer to this question is fluid, and we need to know the pros and cons of each traversal method and be flexible for different scenarios.

conclusion

This article introduces seven HashMap traversal methods. Before JDK 8, EntrySet and KeySet traversal were mainly used. KeySet traversal is not recommended because of its low performance. However, after JDK 8, there are new options for traversal. You can use the simpler Lambda traversal, or you can use the higher performance Stream multithreaded traversal.

Judge right and wrong from yourself, praise to listen to others, gain and loss in the number.

Blogger introduction: programmer after 80 years, writing blog this matter “insist” for 11 years, hobbies: reading, jogging, badminton.

Public number: Java interview analysis