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?
-
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.
Are you confused, wondering why?
Let’s first look at the bytecode generated by the code above, as follows:
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?
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 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.
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 .
Since it cannot be achieved using foreach, how can we achieve it?
There are mainly three methods:
-
Use the remove() method of Iterator
-
Traverse in forward order using for loop
-
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:
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.ConcurrentModificationException
Exception.
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:
After the element “blog garden” is deleted in the first cycle, the subscript of the element becomes as follows:
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:
After the element “Nuggets” is deleted in the first cycle, the subscript of the element becomes as follows:
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:
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:
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:
Welcome to join my knowledge planet, discuss architecture and exchange source code together. How to join, Long press the QR code below:
The source code has been updated on Knowledge Planet and the analysis is as follows:
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 (*^__^*)