java.util.ConcurrentModificationException異常;java.util.ConcurrentModificationException實戰

 

 

寫代碼遇到這個問題,不少博客文章都是在反覆的強調理論,而沒有對應的實例,因此這裏從實例出發,後研究理論: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     }
View Code

打印出結果: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     }
View Code

報錯:

改寫爲:

 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     }
View Code

結果:

      二、整形

  正確添加:

 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 }
View Code

結果:

正確刪除:

 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 }
View Code

 結果:

 (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 }
View Code

結果:

  正確的刪除:

 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 }
View Code

結果:

結果集:

1 [Student{name='李雷', age='13', id='617e914f-ed33-472d-bbbd-1a6bf5ef5901'}, Student{name='韓梅梅', age='14', id='cb804e43-4846-4fc6-84c8-9e4a6b17d7f1'}]
View Code

 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     }
View Code

想要調用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異常。

相關文章
相關標籤/搜索