ArrayList traverses while deleting elements, which may cause bugs!

Sometimes we need to traverse the ArrayList, and then delete the elements according to the conditions, like this:

    public static void main(String[] args) {
        String fff = new String("fff");
        String a=new String();
        ArrayList<String> list= new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        for(String s:list) {
            if("aa".equals(s)) {
                list.remove("aa");
            }
        }
    }

But this will report the following error:

Let's take a look at the decompilation result of the generated class file:

    public static void main(String[] var0) {
        new String("fff");
        new String();
        ArrayList var3 = new ArrayList();
        var3.add("aa");
        var3.add("bb");
        var3.add("cc");
        Iterator var4 = var3.iterator();

        while(var4.hasNext()) {
            String var5 = (String)var4.next();
            if ("aa".equals(var5)) {
                var3.remove("aa");
            }
        }
    }

It can be seen that the traversal here uses the hasNext () and next () methods of the Iterator implemented by ArrayList, but the remove (Object o) method of ArrayList is used for deletion. In this way, the iterator cannot perceive the changes of the elements in the ArrayList. For example, an element has been deleted in the ArrayList, and the elements behind it are moved forward by one position. The element at the original Iterator position is deleted and replaced by the element behind, while Iterator Knowing that, in the next iteration, it will think that this element has been traversed and skip directly.
This behavior will be monitored in ArrayList:
It turns out that ModCount and ExpectedModCount are equal, and ArrayList.remove () is incremented every time ModCount is executed:

Iterator will verify that ModCount and ExpectedModCount are equal:

Then it will throw ConcurrentModificationException

The correct approach:

Take a look at what iterator.remove () does here:

In fact, when calling list.remove (Object o), add a sentence "expectedModCount = modCount;", then their values ​​will be equal in the next iteration.

Supplement:
You can use javac to compile java into a .class file (javac [-encoding utf-8] javaName.java), and then open it in the development tool, you can view the decompiled content of the .class file; or directly in the development tool View class files (decompiled files). To see the specific implementation of some "invisible" methods:
for (String s: list) {
if ("aa" .equals (s)) {
list.remove ("aa");
}
}

String var5;
while (var4.hasNext ()) {
var5 = (String) var4.next ();
if ("aa" .equals (var5)) {
var3.remove ("aa");
Note: If you use jdk With the javap instruction, that is, javap className, you may see the original appearance of the source code only the method name

Guess you like

Origin www.cnblogs.com/superyoungy/p/12682340.html