Java中使用foreach遍歷list的盲點,

我們通常在項目中會用到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。

不過我採用外層是for循環內層是foreach解決此問題:
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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章