我們通常在項目中會用到ArrayList ,喜歡使用jdk1.5以後的foreach進行對list集合遍歷,但是以下的操作會遇到小坑請看代碼:
public class TestListUtils {
public static void main(String[] args) {
ArrayList<Student> a = new ArrayList<Student>();
a.add(new Student(1, "zhao", true, 50.5, new Date()));
a.add(new Student(2, "qian", false, 60.5, new Date()));
a.add(new Student(3, "sun", true, 70.5, new Date()));
a.add(new Student(4, "li", false, 80.5, new Date()));
a.add(new Student(5, "zhou", true, 90.5, new Date()));
a.add(new Student(6, "wu", true, 1000.5, new Date()));
for (Student student : a) {
System.out.println(student);
}
System.out.println("=======================================");
ArrayList<Student> b = new ArrayList<Student>();
b.add(new Student(3, "sun", true, 70.5, new Date()));
b.add(new Student(4, "li", false, 80.5, new Date()));
b.add(new Student(5, "zhou", true, 90.5, new Date()));
for (Student student : b) {
System.out.println(student);
}
for (Student student : a) {
for (int i = 0; i < b.size(); i++) {
a.remove(i);
}
}
}
}
在代碼中的雙層循環中,我們都是使用foreach對list集合操作的,這樣會報錯,如下:Student [id=1, name=zhao, sex=true, score=50.5, birth=Thu Mar 29 11:05:31 CST 2018]
Student [id=2, name=qian, sex=false, score=60.5, birth=Thu Mar 29 11:05:31 CST 2018]
Student [id=3, name=sun, sex=true, score=70.5, birth=Thu Mar 29 11:05:31 CST 2018]
Student [id=4, name=li, sex=false, score=80.5, birth=Thu Mar 29 11:05:31 CST 2018]
Student [id=5, name=zhou, sex=true, score=90.5, birth=Thu Mar 29 11:05:31 CST 2018]
Student [id=6, name=wu, sex=true, score=1000.5, birth=Thu Mar 29 11:05:31 CST 2018]
=======================================
Student [id=3, name=sun, sex=true, score=70.5, birth=Thu Mar 29 11:05:31 CST 2018]
Student [id=4, name=li, sex=false, score=80.5, birth=Thu Mar 29 11:05:31 CST 2018]
Student [id=5, name=zhou, sex=true, score=90.5, birth=Thu Mar 29 11:05:31 CST 2018]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at test_cnbookingapi.TestListUtils.main(TestListUtils.java:36)
ArrayList的父類AbstarctList中有一個域modCount
,每次對集合進行修改(增添元素,刪除元素……)時都會modCount++
而foreach的背後實現原理其實就是Iterator(關於Iterator可以看Java Design Pattern: Iterator),等同於註釋部分代碼。在這裏,迭代ArrayList的Iterator中有一個變量expectedModCount
,該變量會初始化和modCount
相等,但如果接下來如果集合進行修改modCount
改變,就會造成expectedModCount!=modCount
,此時就會拋出java.util.ConcurrentModificationException異常。
解決辦法:
1)在使用iterator迭代的時候使用synchronized或者Lock進行同步;
2)使用併發容器CopyOnWriteArrayList代替ArrayList和Vector。
public class TestListUtils {
public static void main(String[] args) {
ArrayList<Student> a = new ArrayList<Student>();
a.add(new Student(1,"zhao",true,50.5,new Date()));
a.add(new Student(2,"qian",false,60.5,new Date()));
a.add(new Student(3,"sun",true,70.5,new Date()));
a.add(new Student(4,"li",false,80.5,new Date()));
a.add(new Student(5,"zhou",true,90.5,new Date()));
a.add(new Student(6,"wu",true,1000.5,new Date()));
for (Student student : a) {
System.out.println(student);
}
System.out.println("=======================================");
ArrayList<Student> b= new ArrayList<Student>();
b.add(new Student(3,"sun",true,70.5,new Date()));
b.add(new Student(4,"li",false,80.5,new Date()));
b.add(new Student(5,"zhou",true,90.5,new Date()));
for (Student student : b) {
System.out.println(student);
}
//刪除集a中的某個元素
/*for (Student student : a) {
for (int i = 0; i < b.size(); i++) {
a.remove(i);
}
} */
for (int i = 0; i < a.size(); i++) {
for (Student student : b) {
a.remove(i);
}
}
}
}
詳細的講解可以參考此文章:https://www.jianshu.com/p/c5b52927a61a