平時大家for循環應該用的不少,特別是增強for循環,簡單快捷。但是在增強for中做刪除操作,卻會拋出java.util.ConcurrentModificationException,一起來看下。
上面的代碼,在for循環執行完if中的remove,遍歷下一個元素時便會拋出java.util.ConcurrentModificationException。到底在for (String s : list)中發生了什么呢。
ArrayList中有一個內部類Itr,它繼承了Iterator接口。當第一次遍歷增強for循環時,會創建一個Itr對象,注意下圖紅框的部分,變量modCount屬于ArrayList,用來記錄ArrayList被修改的次數,賦值給了Itr類的變量expectedModCount。
然后依次調用Itr的hasNext()和next()方法,取出ArrayList中的元素賦值給for中的變量,注意紅框的方法checkForComodification()。
當執行list.remove(s)時,實則調用其內部的fastRemove(index)做的刪除操作,同時modCount++,但是并沒有重新賦值給Itr類的變量expectedModCount。那么,當遍歷下一個元素調用checkForComodification()方法時,if中的條件就會成立,然后就會拋出ConcurrentModificationException異常。
既然增強for循環中的remove操作會拋異常,那么在普通for循環和迭代器循環中做remove也會拋異常嗎?
普通for循環
普通for循環調用的是remove(int index)方法,不會拋異常,但是需要注意,
1. 如果將for中的i < list.size()替換成i < length,會拋出IndexOutOfBoundsException
2. 在list.remove(i)后,下一次遍歷前,此時i表示第i+1個元素
迭代器循環
迭代器循環調用的是Itr類的remove(int index)方法,不會拋異常,原因是其內部也是調用的ArrayList的remove(int index)方法,但是在之后,有給expectedModCount重新賦值。
所以
增強for循環,實際上還是迭代器遍歷,但是remove操作并沒有同步變量,會導致異常;普通for雖然沒有異常,但是在remove后可能會忽略下標+1而出錯;如果要在遍歷時刪除,最安全就是用迭代器。