寫代碼遇到這個問題,不少博客文章都是在反覆的強調理論,而沒有對應的實例,因此這裏從實例出發,後研究理論:java
1、錯誤產生狀況dom
1 、字符型ide
(1)添加ui
public static void main(String[] args) { List<String> stringList = new ArrayList<String>(); stringList.add("張三毛"); stringList.add("李四"); stringList.add("王五"); stringList.add("錢二"); if (stringList!=null) { if (!stringList.equals(Collections.EMPTY_LIST.isEmpty())){ for (String s : stringList) { stringList.add("趙大"); } } } System.out.println(stringList); }
報錯this
改寫爲以下便可:spa
1 public static void main(String[] args) { 2 3 List<String> stringList = new ArrayList<String>(); 4 stringList.add("張三毛"); 5 stringList.add("李四"); 6 stringList.add("王五"); 7 stringList.add("錢二"); 8 9 if (stringList != null) { 10 if (!stringList.equals(Collections.EMPTY_LIST.isEmpty())) { 11 12 stringList.add("趙大"); 13 14 Iterator<String> it = stringList.iterator(); 15 while (it.hasNext()) { 16 it.next(); 17 } 18 } 19 } 20 21 System.out.println(stringList); 22 23 }
打印出結果:3d
而後咱們打印其next,就會發現其循環就是經過it.next()方法將數據添加進去的code
打印:blog
(2)、刪除繼承
錯誤寫法:
1 private static String key = "錢二"; 2 3 4 public static void main(String[] args) { 5 6 List<String> stringList = new ArrayList<String>(); 7 stringList.add("張三毛"); 8 stringList.add("李四"); 9 stringList.add("王五"); 10 stringList.add("錢二"); 11 12 if (stringList != null) { 13 if (!stringList.equals(Collections.EMPTY_LIST.isEmpty())) { 14 15 for (String s : stringList) { 16 if (key.equals(s)){ 17 stringList.remove(s); 18 } 19 } 20 } 21 } 22 23 System.out.println(stringList); 24 25 }
報錯:
改寫爲:
1 private static String key = "錢二"; 2 3 4 public static void main(String[] args) { 5 6 List<String> stringList = new ArrayList<String>(); 7 stringList.add("張三毛"); 8 stringList.add("李四"); 9 stringList.add("王五"); 10 stringList.add("錢二"); 11 12 if (stringList != null) { 13 if (!stringList.equals(Collections.EMPTY_LIST.isEmpty())) { 14 Iterator<String> it = stringList.iterator(); 15 16 while (it.hasNext()) { 17 String next = it.next(); 18 19 if (key.equals(next)) { 20 it.remove(); 21 } 22 23 } 24 25 } 26 } 27 28 System.out.println(stringList); 29 30 }
結果:
二、整形
正確添加:
1 public class ConcurrentBaseApplication { 2 3 private static String key = "錢二"; 4 5 6 public static void main(String[] args) { 7 8 List<Integer> integerList = new ArrayList<Integer>(); 9 integerList.add(1); 10 integerList.add(2); 11 integerList.add(3); 12 integerList.add(4); 13 14 Integer next=0; 15 16 if (integerList != null) { 17 if (!integerList.equals(Collections.EMPTY_LIST.isEmpty())) { 18 integerList.add(5); 19 20 Iterator<Integer> it = integerList.iterator(); 21 22 while (it.hasNext()) { 23 next = it.next(); 24 System.out.println(next); 25 } 26 27 } 28 } 29 30 System.out.println(integerList); 31 32 } 33 34 }
結果:
正確刪除:
1 public class ConcurrentBaseApplication { 2 3 public static void main(String[] args) { 4 5 List<Integer> integerList = new ArrayList<Integer>(); 6 integerList.add(1); 7 integerList.add(2); 8 integerList.add(3); 9 integerList.add(4); 10 11 if (integerList != null) { 12 if (!integerList.equals(Collections.EMPTY_LIST.isEmpty())) { 13 14 Iterator<Integer> it = integerList.iterator(); 15 16 while (it.hasNext()) { 17 Integer next = it.next(); 18 if("2".equals(next.toString())){ 19 it.remove(); 20 } 21 } 22 } 23 } 24 25 System.out.println(integerList); 26 27 } 28 29 }
結果:
(3) 實體類
建立實體類
Student
package com.north.big.penguin.pojo; import java.io.Serializable; /** * @author liuyangos8888 */ public class Student implements Serializable { /** * 姓名 */ private String name; /** * 年齡 */ private String age; /** * 標識 */ private String id; public Student() { } public Student(String name, String age, String id) { this.name = name; this.age = age; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age='" + age + '\'' + ", id='" + id + '\'' + '}'; } }
正確的添加:
1 public class ConcurrentBaseApplication { 2 3 public static void main(String[] args) { 4 5 List<Student> students = new ArrayList<Student>(); 6 7 Student student1 = new Student(); 8 student1.setName("李雷"); 9 student1.setAge("13"); 10 student1.setId(UUID.randomUUID().toString()); 11 12 Student student2 = new Student(); 13 student2.setName("韓梅梅"); 14 student2.setAge("14"); 15 student2.setId(UUID.randomUUID().toString()); 16 17 Student student3 = new Student(); 18 student3.setName("李華"); 19 student3.setAge("15"); 20 student3.setId(UUID.randomUUID().toString()); 21 22 23 students.add(student1); 24 students.add(student2); 25 students.add(student3); 26 27 if (students != null) { 28 if (!students.equals(Collections.EMPTY_LIST.isEmpty())) { 29 30 Student student4 = new Student(); 31 student4.setName("小明"); 32 student4.setAge("16"); 33 student4.setId(UUID.randomUUID().toString()); 34 35 36 Iterator<Student> it = students.iterator(); 37 38 while (it.hasNext()) { 39 // 添加學生 40 Student next = it.next(); 41 } 42 } 43 } 44 45 System.out.println(students); 46 47 } 48 49 }
結果:
正確的刪除:
1 public class ConcurrentBaseApplication { 2 3 public static void main(String[] args) { 4 5 List<Student> students = new ArrayList<Student>(); 6 7 Student student1 = new Student(); 8 student1.setName("李雷"); 9 student1.setAge("13"); 10 student1.setId(UUID.randomUUID().toString()); 11 12 Student student2 = new Student(); 13 student2.setName("韓梅梅"); 14 student2.setAge("14"); 15 student2.setId(UUID.randomUUID().toString()); 16 17 Student student3 = new Student(); 18 student3.setName("李華"); 19 student3.setAge("15"); 20 student3.setId(UUID.randomUUID().toString()); 21 22 23 students.add(student1); 24 students.add(student2); 25 students.add(student3); 26 27 if (students != null) { 28 if (!students.equals(Collections.EMPTY_LIST.isEmpty())) { 29 30 Student student4 = new Student(); 31 student4.setName("小明"); 32 student4.setAge("16"); 33 student4.setId(UUID.randomUUID().toString()); 34 35 36 Iterator<Student> it = students.iterator(); 37 38 while (it.hasNext()) { 39 // 添加學生 40 Student next = it.next(); 41 42 Integer integerAge = Integer.valueOf(next.getAge()); 43 44 if(integerAge>14){ 45 it.remove(); 46 } 47 } 48 } 49 } 50 51 System.out.println(students); 52 53 } 54 55 }
結果:
結果集:
1 [Student{name='李雷', age='13', id='617e914f-ed33-472d-bbbd-1a6bf5ef5901'}, Student{name='韓梅梅', age='14', id='cb804e43-4846-4fc6-84c8-9e4a6b17d7f1'}]
2、原理補充
繼承關係圖
根據錯誤咱們知道是Itr出錯了
根據添加class,能夠看到它跟ArrayList的關係
Itr是一個內部類,還實現了Iterator
其源碼
1 /** 2 * An optimized version of AbstractList.Itr 3 */ 4 private class Itr implements Iterator<E> { 5 int cursor; // index of next element to return 6 int lastRet = -1; // index of last element returned; -1 if no such 7 int expectedModCount = modCount; 8 9 Itr() {} 10 11 public boolean hasNext() { 12 return cursor != size; 13 } 14 15 @SuppressWarnings("unchecked") 16 public E next() { 17 checkForComodification(); 18 int i = cursor; 19 if (i >= size) 20 throw new NoSuchElementException(); 21 Object[] elementData = ArrayList.this.elementData; 22 if (i >= elementData.length) 23 throw new ConcurrentModificationException(); 24 cursor = i + 1; 25 return (E) elementData[lastRet = i]; 26 } 27 28 public void remove() { 29 if (lastRet < 0) 30 throw new IllegalStateException(); 31 checkForComodification(); 32 33 try { 34 ArrayList.this.remove(lastRet); 35 cursor = lastRet; 36 lastRet = -1; 37 expectedModCount = modCount; 38 } catch (IndexOutOfBoundsException ex) { 39 throw new ConcurrentModificationException(); 40 } 41 } 42 43 @Override 44 @SuppressWarnings("unchecked") 45 public void forEachRemaining(Consumer<? super E> consumer) { 46 Objects.requireNonNull(consumer); 47 final int size = ArrayList.this.size; 48 int i = cursor; 49 if (i >= size) { 50 return; 51 } 52 final Object[] elementData = ArrayList.this.elementData; 53 if (i >= elementData.length) { 54 throw new ConcurrentModificationException(); 55 } 56 while (i != size && modCount == expectedModCount) { 57 consumer.accept((E) elementData[i++]); 58 } 59 // update once at end of iteration to reduce heap write traffic 60 cursor = i; 61 lastRet = i - 1; 62 checkForComodification(); 63 } 64 65 final void checkForComodification() { 66 if (modCount != expectedModCount) 67 throw new ConcurrentModificationException(); 68 } 69 }
想要調用iteror轉化ArrayList就要找iterator方法
Itr參數解析
參數 | 含義 |
cursor | 一個索引,表明下一個要訪問的元素的索引 |
astRet | 表示上一個訪問的元素的索引 |
expectedModCount | 表示修改次數的 |
modCount | 表示對List的修改次數 |
其方法主要是hasNext()和next()兩個方法,
用其判斷是否還有元素未被訪問,代碼中
while(iter.hasNext()){
}
若是下一個訪問的元素下標不等於ArrayList的大小,就表示有元素須要訪問,這個很容易理解,若是下一個訪問元素的下標等於ArrayList的大小,則確定到達末尾了。
首先在next()方法中會調用checkForComodification()方法,而後根據cursor的值獲取到元素,接着將cursor的值賦給lastRet,並對cursor的值進行加1操做。初始時,cursor爲0,lastRet爲-1,那麼調用一次以後,cursor的值爲1,lastRet的值爲0。注意此時,modCount爲0,expectedModCount也爲0。
當判斷當前元素的值是否爲2,若爲2,則調用list.remove()方法來刪除該元素。
ArrayList中的remove
經過remove方法刪除元素最終是調用的fastRemove()方法,在fastRemove()方法中,首先對modCount進行加1操做(由於對集合修改了一次),而後接下來就是刪除元素的操做,最後將size進行減1操做,並將引用置爲null以方便垃圾收集器進行回收工做。
執行完刪除操做後,繼續while循環,調用hasNext方法()判斷,因爲此時cursor爲1,而size爲0,那麼返回true,因此繼續執行while循環,而後繼續調用iterator的next()方法.
若是modCount不等於expectedModCount,則拋出ConcurrentModificationException異常。
此時modCount爲1,而expectedModCount爲0,所以程序就拋出了ConcurrentModificationException異常。