It has been developed for 5 years, and the elements in the List will not be deleted cyclically. Is it so difficult?

Click on the “Java base” above, select “Set as star”

Be a positive person, not a positive waste person!

Update articles every day at 14:00, lose a million bits of hair every day…

Source code boutique column

  • Original | Java 2021 Super God Road, very liver~

  • An open source project with detailed annotations in Chinese

  • RPC framework Dubbo source code analysis

  • Network application framework Netty source code analysis

  • Message middleware RocketMQ source code analysis

  • Database middleware Sharding-JDBC and MyCAT source code analysis

  • Job Scheduling Middleware Elastic-Job Source Code Analysis

  • Distributed transaction middleware TCC-Transaction source code analysis

  • Eureka and Hystrix source code analysis

  • Java Concurrency Source Code

Source: juejin.im/post/

5e93ce3be51d45470d528262

  • 1. Common mistakes made by novices

  • 2. Use the remove() method of Iterator

  • 3. Use the for loop to traverse in positive order

  • 4. Use the for loop to traverse in reverse order

  • 5. Clarification of doubts in the comment area (updated on 2020-06-15)

    • 5.1 Use the removeIf() method (recommended)

    • 5.2 When using the for loop to traverse in positive order, do I need to correct the subscript?

f98bcf1605e8e741c19599e649c46c0b.jpeg

This is an interview question that was asked during a recent interview. This blog summarizes and shares this question.

1. Common mistakes made by novices

Maybe many novices (including me back then, haha) first thought of writing as follows:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("blog garden");
    platformList.add("CSDN");
    platformList.add("Nuggets");

    for (String platform : platformList) {
        if (platform.equals("Blog Garden")) {
            platformList. remove(platform);
        }
    }

    System.out.println(platformList);
}

Then I ran it with confidence, and the result was that a java.util.ConcurrentModificationException was thrown. The translation into Chinese is: concurrent modification exception.

eef73d6eadfea7d0718a17a619c31e77.jpeg

Are you confused, wondering why?

Let’s first look at the bytecode generated by the code above, as follows:

a2c814600a8c9b1fd4f7031c1c4ee8ab.jpeg

It can be seen from this that when the foreach loop is actually executed, it actually uses Iterator, and the core methods used are hasnext() and next() code>.

Then let’s take a look at how the Iterator of the ArrayList class is implemented?

2a2db77a6856e06179f53be31cba2c00.jpeg

It can be seen that when the next() method is called to get the next element, the first line of code calls checkForComodification();, and the core logic of this method is to compare the modCount and expectedModCount.

In the above example, the values of modCount and expectedModCount are both 3 at the beginning, so it is no problem to get the element “blog garden” for the first time, but when the execution is finished When following this line of code:

platformList. remove(platform);

The value of modCount is changed to 4.

fa36707bb7a7888ece5a8579bf0547cb.jpeg

So when the element is acquired for the second time, the values of modCount and expectedModCount are not equal, so a java.util.ConcurrentModificationException is thrown .

2b9c35151e762734a24ca0272fbe6069.jpeg

Since it cannot be achieved using foreach, how can we achieve it?

There are mainly three methods:

  1. Use the remove() method of Iterator

  2. Traverse in forward order using for loop

  3. Use a for loop to traverse in reverse order

Let me explain them one by one.

Background management system + user applet based on Spring Boot + MyBatis Plus + Vue & amp; Element, supports RBAC dynamic permissions, multi-tenancy, data permissions, workflow, three-party login, payment, SMS, mall and other functions

  • Project address: https://github.com/YunaiV/ruoyi-vue-pro

  • Video tutorial: https://doc.iocoder.cn/video/

2. Use the remove() method of Iterator

The implementation of the remove() method using Iterator is as follows:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("blog garden");
    platformList.add("CSDN");
    platformList.add("Nuggets");

    Iterator<String> iterator = platformList. iterator();
    while (iterator. hasNext()) {
        String platform = iterator. next();
        if (platform.equals("Blog Garden")) {
            iterator. remove();
        }
    }

    System.out.println(platformList);
}

The output is:

[CSDN, Nuggets]

Why use iterator.remove();?

Let’s take a look at its source code:

04100feb201f62a86f3f661c1fc9dbf5.jpeg

It can be seen that every time an element is deleted, the value of modCount will be reassigned to expectedModCount, so that the two variables are equal and will not trigger java. util.ConcurrentModificationExceptionException.

Background management system + user applet based on Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & amp; Element, supporting RBAC dynamic permissions, multi-tenancy, data permissions, workflow, three-party login, payment, SMS, mall and other functions

  • Project address: https://github.com/YunaiV/yudao-cloud

  • Video tutorial: https://doc.iocoder.cn/video/

3. Use the for loop to traverse in positive order

The implementation of forward order traversal using for loop is as follows:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("blog garden");
    platformList.add("CSDN");
    platformList.add("Nuggets");

    for (int i = 0; i < platformList. size(); i ++ ) {
        String item = platformList. get(i);

        if (item.equals("Blog Garden")) {
            platformList. remove(i);
            i = i - 1;
        }
    }

    System.out.println(platformList);
}

This implementation method is easier to understand, that is, to delete through the subscript of the array, but there is a note that after deleting the element, the value of the subscript must be corrected:

i = i - 1;

Why should the value of the subscript be corrected?

Because the subscript of the initial element is like this:

2794d34735ff062c10ab2ec2d32995f3.jpeg

After the element “blog garden” is deleted in the first cycle, the subscript of the element becomes as follows:

27b44b9c47f7bba5594a63e32f059efa.jpeg

In the second cycle, the value of i is 1, that is, the element “Nuggets” is taken, which causes the element “CSDN” to be skipped for inspection, so after deleting the element, we need to correct the subscript, which is also the above The purpose of i = i - 1; in the code.

4. Use the for loop to traverse in reverse order

The implementation of reverse traversal using the for loop is as follows:

public static void main(String[] args) {
    List<String> platformList = new ArrayList<>();
    platformList.add("blog garden");
    platformList.add("CSDN");
    platformList.add("Nuggets");

    for (int i = platformList. size() - 1; i >= 0; i--) {
        String item = platformList. get(i);

        if (item.equals("Nuggets")) {
            platformList. remove(i);
        }
    }

    System.out.println(platformList);
}

This implementation is similar to using the for loop to traverse in positive order, but there is no need to modify the subscript, because the subscript of the element at the beginning is like this:

22fe56236421823ff54587a8ce44a2ce.jpeg

After the element “Nuggets” is deleted in the first cycle, the subscript of the element becomes as follows:

91942d9918eccb58c1d73b5c9a071ecd.jpeg

The value of i in the second loop is 1, that is, the element “CSDN” is fetched, which will not cause the element to be skipped, so there is no need to modify the subscript.

5. Comment area clarification (2020-06-15 update)

5.1 Use removeIf() method (recommended)

Starting from JDK1.8, you can use the removeIf() method to replace the remove() method of Iterator to delete while traversing. In fact, IDEA will also prompt:

7f966de0ecc428cfa30f2e442e55c30f.jpeg

So the original code:

Iterator<String> iterator = platformList.iterator();
while (iterator. hasNext()) {
    String platform = iterator. next();
    if (platform.equals("Blog Garden")) {
        iterator. remove();
    }
}

It can be simplified to 1 line of code as shown below, which is very concise:

platformList.removeIf(platform -> "Blog Garden".equals(platform));

Looking at the source code of the removeIf() method, you will find that the remove() method of Iterator is also used at the bottom layer:

c83c0a349967568878d28ba7d531b774.jpeg

5.2 Do I need to correct the subscript when using the for loop to traverse in positive order?

Let me talk about the conclusion first: need.

However, the examples given in the previous article are not very good, so many readers think that it is possible not to modify the subscript after reading it. In fact, it is not. Let’s use another example to understand:

List<String> platformList = new ArrayList<>();
platformList.add("blog garden");
platformList.add("blog garden");
platformList.add("CSDN");
platformList.add("Nuggets");

for (int i = 0; i < platformList. size(); i ++ ) {
 String item = platformList. get(i);
    if ("Blog Garden".equals(item)) {
     platformList. remove(i);
    }
}

System.out.println(platformList);

Output result:

[Blog Garden, CSDN, Nuggets]

It can be found that if the subscript is not corrected, the second element “blog garden” will be skipped during the loop traversal and cannot be deleted, so the subscript must be corrected:

d4fec6e9c2d5540db39061794e91cd63.jpeg

Welcome to join my knowledge planet, discuss architecture and exchange source code together. How to join, Long press the QR code below:

1128502e3d84326d5a8074f0f9c66bab.png

The source code has been updated on Knowledge Planet and the analysis is as follows:

6e39ac691d2dfe3881bde8eb293f4567.jpeg

1e645001eed5a34a9724fbe3108cff2f.jpeg

2ad2441c32e21b35434b078d9c55f04a.jpeg

76e2079594cdb20b9aa0e9cf59c08901.jpeg

The recently updated series “Introduction to Taro SpringBoot 2.X” has more than 101 articles, covering MyBatis, Redis, MongoDB, ES, sub-database and sub-table, read-write separation, SpringMVC, Webflux, permissions, WebSocket, Dubbo, RabbitMQ, RocketMQ , Kafka, performance testing, etc.

Provides a SpringBoot example with nearly 3W lines of code, and an e-commerce microservice project with more than 6W lines of code.

How to get it: Click “Looking“, follow the official account and reply to 666 to receive, more content will be provided one after another.

If the article is helpful, please read it and forward it.
Thank you for your support (*^__^*)