這個問題看似好像挺簡單挺幼稚的,然而就這個幼稚的問題還曾經困擾過我一陣呢,其實犯這個錯誤的根本緣由是咱們對於基礎知識的理解和掌握上還有不足的表現,基本功有些人老是以爲不重要,認爲更多的擴大學習的廣度纔是最重要的,我認爲這是很容易犯的,同時也是很致命的錯誤觀點!java
對基礎知識掌握不牢靠,或理解不深入,寫出的代碼必然會有40%的機率是錯誤的、低效的,一段代碼不是說沒有編譯錯誤就必定是對的,不是說簡單的運行下就必定是對的,優秀的代碼,是經得起「刀山火海」般的考驗的(「多線程、效率、安全」這三坐大山)。編程
因此重要性,我就再也不強調了,相信說完後,地球人都能懂個人意思,那麼下面就來看看這個有趣的現象吧。安全
先看看以下代碼多線程
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class TestList { void init(List<Integer> list) { list.clear(); for (int i = 0; i < 10; i++) { list.add(i + 1); } } void remove(List<Integer> list) { for (int i = 0; i < 5; i++) { list.remove(i); } } void removeTwo(List<Integer> list) { for (int i : list) { if (i < 6) { list.remove(i); } } } void removeThree(List<Integer> list) { for (Iterator<Integer> iter = list.iterator(); iter.hasNext();) { int i = iter.next(); if (i < 6) { iter.remove(); } } } public static void main(String[] args) { TestList testList = new TestList(); List<Integer> list = new ArrayList<Integer>(); // 第一種方法 testList.init(list); testList.remove(list); System.out.println(list); // 第二種方法 try { testList.init(list); testList.removeTwo(list); System.out.println(list); } catch (Exception e) { e.printStackTrace(); } // 第三種方法 testList.init(list); testList.removeThree(list); System.out.println(list); } }
運行的結果以下:學習
[2, 4, 6, 8, 10]spa
java.util.ConcurrentModificationException線程
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)code
at java.util.AbstractList$Itr.next(AbstractList.java:343)orm
at com.TestList.removeTwo(TestList.java:23)對象
at com.TestList.main(TestList.java:60)
[6, 7, 8, 9, 10]
上面代碼邏輯很簡單,就是將List集合裏的前5個對象刪除掉,然而結果倒是至關不同:第一個是錯誤的結果,第二個直接報異常,只有第三個是咱們想要的結果!
那麼這是爲何呢?其實主要緣由來自於List中的remove()方法。咱們來分析一下:
第一種方法:
第一次執行完remove方法後,並不像咱們簡單想象的那樣就把第一個刪除了,「1」這個對象被刪除了沒錯,可是當被刪除後List中「2」之後的9個對象的index索引也變了,都比原來的值減一,換句話說就是剩下的9個對象的index值爲從0到8,而不是原來的從1到9了,那麼第二次執行remove方法時,此時list.remove(1)刪除的就是「3」這個對象(「3」的index值爲1),而不是咱們想象的刪除「2」對象。
第二種方法:
緣由跟上面同樣,致使List的next()方法內部出現modCount和expectedModCount不一致致使拋出異常。
因此咱們這裏建議你們採用第三種方法來刪除List集合中某一個對象,這樣作是最簡單且容易記憶的。那第一種方法和第二種方法有沒有解決的辦法呢?目前我知道第一種方法的解決辦法,第二種應該是無解的(由於語法結構致使)。
第一種方法的改進措施:
void remove(List<Integer> list) { int num = list.size() - 5; for (int i = 0; i < num; i++) { list.remove(i); i--; num--; } }
我想你編程時間長了,也會偶爾遇到這些相似簡單卻讓你頭疼的問題,遇到這些問題首先檢查下本身的邏輯是否有問題,若是邏輯沒有問題就檢查下代碼的結構是否有問題吧,這就是所謂的基本功,之後我也會慢慢的增強鞏固本身基本功方面的能力,一塊兒加油吧。