preface

“Like” is a habit.

Click like collection, brilliant life.

Click on [wechat search public number: Programming back pot man] to prevent getting lost.

ArrayList series

Constructor in ArrayList (ArrayList) Sorry I’m not ready!! Add, addAll (ArrayList, ArrayList, ArrayList, ArrayList, ArrayList, ArrayList) ArrayList remove, removeAll, clear method source code to report on the four: ArrayList hammer method to exercise the source get, set, contains, isEmpty method!! Article 5: red full screen, operation of the ArrayList Iterator methods should give me a quote ConcurrentModificationException anomalies

Deletion Method table

The method name describe
public String toString() Convert all the data in the collection to a string
public Iterator iterator() Plain iterator
public int indexOf(Object o) Clear the collection
public int lastIndexOf(Object o) Removes elements identical to those in the given collection
default void remove() The remove method in the iterator inside the ArrayList removes elements from the collection
java.util.ConcurrentModificationException Iterator ConcurrentModificationException anomalies

Public String toString() converts all the data in the collection to a String

Case presentation

@Test
public void test_toString(a){
 ArrayList<String> list = new ArrayList<>();
 list.add("Lo lo 01");
 list.add("Lo lo 02");
 // Convert all the data in the collection to a string  String x = list.toString();  System.out.println(x); } Copy the code

Source code analysis

// Convert all the data in the collection to a string
public String toString(a) {
  Iterator () : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator()
 Iterator<E> it = iterator();
  // Call the hasNext method in the ArrayList to see if there are elements. If hasNext() returns false
 // The toString method returns a "[]"  if (! it.hasNext())  return "[]";  // Create a StringBuilder to concatenate the contents of the collection to avoid frequent concatenation of strings resulting in many invalid objects  StringBuilder sb = new StringBuilder();  // Concatenates the left bracket of the string  sb.append('[');  // iterate indefinitely  for (;;) {  // Call the next method in ArrayList to fetch the element  E e = it.next();  sb.append(e == this ? "(this Collection)" : e);  // Call the hasNext method in the ArrayList to see if there are elements. If hasNext() returns false  // Then concatenate an "]" and convert it to toString  if (! it.hasNext())  return sb.append('] ').toString();  // Concatenate element delimiters [,] comma, space  sb.append(', ').append(' ');  } }  // The Iterator method in ArrayList, the inner class of ArrayList collection public class ArrayList<E> extends AbstractList<E>  implements List<E>, RandomAccess.Cloneable.java.io.Serializable {   // Returns an object of the Iterator class inside the ArrayList collection  public Iterator<E> iterator(a) {  return new Itr();  }   // ArrayList implements the Iterator class internally  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  // Assign the actual number of changes to the expected number of changes. Note that only one is assigned  // Each time the iterator gets the element, it will determine whether the actual number of changes is the same as the expected number of changes  // If inconsistent, a concurrent modification exception is generated  int expectedModCount = modCount;   Itr() {}   // Determine whether the size of the cursor and the set are not equal  public boolean hasNext(a) {  returncursor ! = size; }   // Get the next element, as explained in the source code analysis below  @SuppressWarnings("unchecked")  public E next(a) {  checkForComodification();  int i = cursor;  if (i >= size)  throw new NoSuchElementException();  Object[] elementData = this.elementData;  if (i >= elementData.length)  throw new ConcurrentModificationException();  cursor = i + 1;  return (E) elementData[lastRet = i];  }   // Concurrent modification exception  final void checkForComodification(a) {  // If the expected number of changes is not equal to the actual number of changes, a concurrent change exception is generated  if(modCount ! = expectedModCount) throw new ConcurrentModificationException();  }  } } Copy the code

conclusion

Returns a string representation of this collection. If the collection is empty, return “[]”. Returns “[element, element]” if there are elements in the collection

List of ‘,’ and space-separated strings.

Public Iterator Iterator () A plain Iterator

Case presentation

@Test
public void test_toString_ie(a){
 ArrayList<String> list = new ArrayList<>();
 list.add("Lo lo 01");
 list.add("Lo lo 02");
 list.add("Lo lo 03");  // Get the iterator  Iterator<String> iterator = list.iterator();  // iterate over the collection  while (iterator.hasNext()){  String next = iterator.next();  System.out.println(next);  } } Copy the code

Source code analysis

public class ArrayList<E> extends AbstractList<E>
  implements List<E>, RandomAccess.Cloneable.java.io.Serializable {
 
  // ArrayList inner class
  // It is important to observe several member variables in the Itr class
 public Iterator<E> iterator(a) {  return new Itr();  }   private class Itr implements Iterator<E> {  // Return the index of the element next  int cursor; // index of next element to return  // The last one returns the index of the element  int lastRet = -1; // index of last element returned; -1 if no such  // Assign the actual number of changes to the expected number of changes  // During iteration, concurrent modification exceptions occur whenever the actual and expected number of modifications are inconsistent  ExpectedModCount is a member of the Itr, so it is only assigned once!!  ExpectedModCount is also 3 because the add method is called three times, so the actual number of times the set is modified is 3  int expectedModCount = modCount;   Itr() {}   // Determine if there is a next element  public boolean hasNext(a) {  returncursor ! = size; }   // Get the next element  @SuppressWarnings("unchecked")  public E next(a) {  / / check whether modify the number of times and the number of expected equal, not equal to throw ConcurrentModificationException  checkForComodification();  // Assign the index of the next element to I  int i = cursor;  If the index is greater than the length of the collection, NoSuchElementException is thrown  if (i >= size)  throw new NoSuchElementException();  // Assign the array of data stored at the bottom of the collection to the iterator's local variable elementData  Object[] elementData = ArrayList.this.elementData;  // Again, if the index of the next element is greater than the length of the underlying stored element in the collection, concurrent modification is abnormal  // Note that the result shown here is not what we want, although a concurrent modification exception is generated  if (i >= elementData.length)  throw new ConcurrentModificationException();  // Each time an element is successfully fetched, the index of the next element is the current index +1  cursor = i + 1;  // Return the element  return (E) elementData[lastRet = i];  }   final void checkForComodification(a) {  // If the expected number of changes is not equal to the actual number of changes, a concurrent change exception is generated  if(modCount ! = expectedModCount) throw new ConcurrentModificationException();  }  } } Copy the code

conclusion

Loop through the collection using an iterator, which is an iterator from the ArrayList source code. The hasNext method is used to determine if the next element exists, and the next method is used to get the element.

The number of times modCount is modified and the expected number of times expectedModCount need to be noticed.

Public int indexOf(Object o) queries the indexOf the first occurrence of a given element in the collection

Case presentation

@Test
public void test_indexOf(a){
 ArrayList<String> list = new ArrayList<>();
 list.add("Lo lo 01");
 list.add("Lo lo 02");
 list.add("Lo lo 02");  list.add("Lo lo 03");   int i = list.indexOf("Lo lo 02");  System.out.println(i);/ / 1 } Copy the code

Source code analysis

// Get the index of the specified value o in the collection
public int indexOf(Object o) {
  // Check whether the value is null
 if (o == null) {
    // Loop through the collection
 for (int i = 0; i < size; i++)  // Find the set whose first value is null and return the index of that value  if (elementData[i]==null)  return i;  } else {  // The given value o is not null, loop over the set  for (int i = 0; i < size; i++)  // Determine if there is a given equal element in the set, and return the index of that value if there is  if (o.equals(elementData[i]))  return i;  }  The given value o does not exist in the set, returns -1  return -1; } Copy the code

conclusion

Gets the index of the specified value o in the collection. Returns -1 if the set does not contain the given element. Returns the index from which the element was first found.

Public int lastIndexOf(Object O) Queries the index of the last occurrence of a given element in the set

Case presentation

@Test
public void test_lastIndexOf(a){
 ArrayList<String> list = new ArrayList<>();
 list.add("Lo lo 01");
 list.add("Lo lo 03");
 list.add("Lo lo 02");  list.add("Lo lo 03");  list.add("Lo lo 03");  // Get the elements in the set equal to "Lolo 03" in reverse order  int i = list.lastIndexOf("Lo lo 03");  System.out.println(i);/ / 4 } Copy the code

Source code analysis

// // gets the index of the specified value o in the collection
public int lastIndexOf(Object o) {
  // Check whether the value is null
 if (o == null) {
    // If null is specified, loop over the set in reverse order
 for (int i = size-1; i >= 0; i--)  // Check if there is null and return index I  if (elementData[i]==null)  return i;  } else {  // The given value is not null, and the collection is traversed backwards  for (int i = size-1; i >= 0; i--)  // // determines if there is a given equal element in the set, and if there is, returns the index of the value  if (o.equals(elementData[i]))  return i;  }  // There is no given value in the collection, return -1  return -1; } Copy the code

conclusion

Gets the index of the specified value o in the collection. Returns -1 if the set does not contain the given element. Returns the index where the element was last found. The loop in the source code is traversal in reverse order.

The remove method in the default void remove() iterator removes elements from the collection

Code demo

@Test
public void test_iterator_remove(a){
 ArrayList<String> list = new ArrayList<>();
 list.add("Lo lo 01");
 list.add("Lo lo 02");
 list.add("Lo lo 02");  list.add("Lo lo 03");  // This blob of code will be replaced with the removeIf method below, using JDK lambda expressions instead  Iterator<String> iterator = list.iterator();  while (iterator.hasNext()){  String next = iterator.next();  if (next.equals("Lo lo 02")) { iterator.remove();  }  }  list.forEach(System.out::println); }  // The removeIf method can simplify a lot of code @Test public void test_iterator_remove(a){  ArrayList<String> list = new ArrayList<>();  list.add("Lo lo 01");  list.add("Lo lo 02");  list.add("Lo lo 02");  list.add("Lo lo 03");  list.removeIf(next -> next.equals("Lo lo 02"));  list.forEach(System.out::println); } Copy the code

Source code analysis

public class ArrayList<E> extends AbstractList<E>
  implements List<E>, RandomAccess.Cloneable.java.io.Serializable {

 // ArrayList inner class
 // It is important to observe several member variables in the Itr class
 public Iterator<E> iterator(a) {  return new Itr();  }   private class Itr implements Iterator<E> {  // Return the index of the element next  int cursor; // index of next element to return  // The last one returns the index of the element  int lastRet = -1; // index of last element returned; -1 if no such  // Assign the actual number of changes to the expected number of changes  // During iteration, concurrent modification exceptions occur whenever the actual and expected number of modifications are inconsistent  ExpectedModCount is a member of the Itr, so it is only assigned once!!  // Since the add method is called three times, the actual number of times the set is modified is 3, so the value of the expectedModCount is also 4  int expectedModCount = modCount;  // No argument constructor  Itr() {}   // The iterator deletes an element  public void remove(a) {  // Check whether the index of the returned element is less than 0.  if (lastRet < 0)  throw new IllegalStateException();  // Check whether concurrent modification exceptions occur. The first call does not, because the number of changes is the same as the actual number of changes  checkForComodification();   try {  // The method that actually removes the collection element, passing 0 as an argument  The source code analysis of this method is available in another article in the ArrayList series  ArrayList.this.remove(lastRet);  // Assign lastRet to cursor  cursor = lastRet;  // Again equal to -1  lastRet = -1;  // Assign the actual number of changes to the expected number of changes again, regardless of whether the collection itself was deleted successfully  // Then the actual number of changes is the same as the expected number of changes, so there is no concurrent change exception  expectedModCount = modCount;  } catch (IndexOutOfBoundsException ex) {  throw new ConcurrentModificationException();  }  }   } } Copy the code

Iterators in Java. Util. ConcurrentModificationException anomalies

Case presentation

@Test
public void test_toString_CME_01(a){
 List<String> list = new ArrayList<>();
 list.add("Lo lo 01");
 list.add("Lo lo 02");
 list.add("Lo lo 03");  Iterator<String> iterator = list.iterator();  while (iterator.hasNext()){  String next = iterator.next();  if (next.equals("Lo lo 03")) { / / this one line of code that can lead to abnormal ConcurrentModificationException  / / why this line of code can cause abnormal ConcurrentModificationException?  // What happened?  list.remove("Lo lo 03");  }  }  System.out.println(list.toString()); }  / / in view of the above will be abnormal ConcurrentModificationException, can use iterator own the remove method to avoid this exception @Test public void test_toString_CME_01(a){  List<String> list = new ArrayList<>();  list.add("Lo lo 01");  list.add("Lo lo 02");  list.add("Lo lo 03");  Iterator<String> iterator = list.iterator();  while (iterator.hasNext()){  String next = iterator.next();  if (next.equals("Lo lo 03")) { // This method resolves the above exception  iterator.remove();  }  }  System.out.println(list.toString()); }  Copy the code

Generate exception source code

final void checkForComodification(a) {
  / / set to modify the number of times is not equal to the number of desired changes expectedModCount throw ConcurrentModificationException
 if(modCount ! = expectedModCount)    // This is where the exception comes from
  throw new ConcurrentModificationException();
} Copy the code

Abnormal prompt

java.util.ConcurrentModificationException
 at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
 at java.util.ArrayList$Itr.next(ArrayList.java:859)
Copy the code

Abnormal analysis

Check the number of times the modCount value is modified and the expectedModCount value is modified

! [image-20200706184112106](/Users/fenke/Library/Application Support/typora-user-images/image-20200706184112106.png)

conclusion

  • For the above example and the two diagrams,debug tests will find that iterator.next() is faulty, which is actually a checkForComodification error.

  • For the above example, the cause of the reported exception is expectedModCount 3. This value is actually derived from the internal Itr class in the ArrayList source code, which is given when the list.iterator() method is called.

  • However, we modified modCount for 4 times in total, including 3 add and 1 remove operations.

  • This is the exception caused by the last list.remove operation. This method is the ArrayList method. The modCount method that operates on this will not be synchronized to the expectedModCount in the Itr. So these two values are not equal, so this exception is reported. You can use the Itr’s own remove method.

  • The exception occurs at String next = iterator.next(); This line of code. Iterator.hasnext () is a successful implementation of iterator.hasnext ().

Your likes, comments and concerns are the biggest support and encouragement for me, and your support and encouragement for me to continue to create high-quality blog!!

The nuggets essay | 2020 years and I summarize the campaign is under way…