1. Test code
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); for(int index = 0 ; index < list.size() ; index++){ if(Objects.equals("a", list.get(index))){ list.remove(index); } } System.out.println(String.valueOf(list));
2. Implementation principle
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ // Remove the element at the specified position in the list. // All subsequent elements are shifted left (subscript minus 1). public E remove(int index) { rangeCheck(index); // Whether it is out of bounds, whether the index is greater than the length of the array modCount++; // number of operations E oldValue = elementData(index); int numMoved = size - index - 1; // Copy numMoved elements after index+1 to the position of index // Overwrite the element at the index position, set the extra position to null, and wait for GC if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
3. In other cases, this method can be used to
delete a single element, but not in the case of multiple elements,
because after deleting an element, the size of the array and the subscript of the original element will change; it needs to be dealt with accordingly.
ArrayList<String> list1 = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); for(int index = 0 ; index < list1.size() ; index++){ // After deleting index = 0, that is, after element a, the size of the array becomes 3, and the subscript of b becomes 0, so c is deleted again, and finally exits the loop list1.remove(index); } System.out.println(String.valueOf(list1));
Second, foreach
1. Code implementation
for (String s : list) { if (s.equals("a")) list.remove(s); }
Running throws
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForCommodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
2 .Anomaly Analysis
// where the exception was thrown final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } /** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForCommodification();// Corresponding 831 lines of code 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]; } }
The chcek was performed during the traversal process from the abnormal information of the positioning
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
modCount is the actual number of operations on the array, expectedModCount is the expected number of operations
Initialization
int expectedModCount = modCount;
But at the same time of traversing, the remove operation is performed, resulting in modCount+1, which is inconsistent with expectedModCount
3. Why does the method of deleting elements call Next
java foreach implementation principle In the implementation principle
of foreach, the essence of foreach is the implementation of Iterator
/** * Returns an iterator over the elements in this list in proper sequence. * * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @return an iterator over the elements in this list in proper sequence */ public Iterator<E> iterator() { return new Itr(); } /** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> {}
The implementation process of deleting elements
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }
That is, it can be considered that the Iterator method of the ArrayList is called, and the static class Itr, which is implemented internally, is returned.
In the process of foreach, that is, in the process of the next operation of the Iterator, a check will be performed each time before the next element is obtained.
Throwing is not allowed at the same time. Exceptions for modifying operations
3. Iterator
Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ if(StringUtils.isNotEmpty(iterator.next())){ iterator.remove(); } }
Convert a collection to an Iterator Use an Iterator to delete a collection.