Pay attention! Add or delete ArrayList. Do not use it indiscriminately

Time:2020-4-11

In the process of programming, we often need to use the collection, and ArrayList is often used by us, but recently there are some problems in a deletion and increase, share the record.

Here are two sections of code

List arrayList1 = new ArrayList();
arrayList1.add("1");
arrayList1.add("2");
for (String s : arrayList1) {
    if("1".equals(s)){
        arrayList1.remove(s);
    }}
    List arrayList2 = new ArrayList();
    arrayList2.add("2");arrayList2.add("1");
    for (String s : arrayList2) {
        if("1".equals(s)){
        arrayList2.remove(s);
    }
}

The running results of the program are as follows:

The remove method of arraylist1 was executed successfully,
The remove method run of arraylist2 threw a concurrentmodificationexception.

Let’s look at the source code to analyze the cause of the exception
Because the essence of foreach is to use iterator, all collaboration collection classes will implement Iterable interface.
Find the iterator () method of the ArrayList class

public Iterator iterator() {
    return new Itr();
}

The essence of an iterator is to first call the hasnext() method to determine whether the next element exists, and then use the next() method to remove the next element

public boolean hasNext() {
    return cursor != size;
}

@SuppressWarnings("unchecked")
public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object\[\] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData\[lastRet = i\];
}

Why can arraylist1 above remove successfully? In fact, it only circulates once, so it succeeds.

Because after the remove element 1, its size-1 becomes 1, and then the cursor variable inside ITR changes from 0 to 1. At this time, 1 = 1, the loop ends, so it succeeds.

Why does arraylist2 fail to remove? Because it succeeds in removing the second time in the loop, but the value of cursor is 2 in the third time when judging next, which does not equal to the current size 1, so the next method is executed. The most important thing is that the previous operation of remove causes the modcount value of ArrayList to be increased by 1, and then the expectedmodcount in ITR class remains unchanged, so an exception will be thrown.

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

Similarly, since the add operation will also cause the modcount to increase automatically, it is not allowed to delete, add or modify the elements in the ArrayList in foreach.

In this regard, we recommend that you use iterator to delete elements.

Iterator ite = arrayList2.iterator();
while(ite.hasNext()) {
    if("1".equals(ite.next())) {
        ite.remove();
    }
}

If there are concurrent operations, you also need to lock the iterator.

Author: struggling little programmer
https://www.toutiao.com/i6754322606561690116/

Recommend to my blog to read more:

1. Java JVM, collection, multithreading, new features series tutorial

2. Spring MVC, spring boot, spring cloud series tutorials

3. Tools tutorials of maven, GIT, eclipse and IntelliJ idea

4. Latest interview questions of Java, backend, architecture, Alibaba and other large factories

Life is beautiful. See you tomorrow