1.ConcurrentModificationException
有如下代碼處理ArrayList
@Test
public void test1() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
for(int num: list) {
if (num == 2) {
list.remove(num);
}
}
System.out.println(StringUtils.join(list, ","));
}
代碼運行起來會報如下錯誤:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
...
2.分析
https://juejin.im/post/5a992a0d6fb9a028e46e17ef
上面的文章分析得挺詳細的,就不復制粘貼了。簡單總結一下就是:
ArrayList拋異常的位置源碼如下
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
modCount是ArrayList本身的屬性,expectedModCount是ArrayList內部類Iterator的屬性。
理論上他們是同步的,但是我們在某些操作的過程中導致會導致他們不一致,比如說在這個例子中,我們調用的是ArrayList.remove()方法,修改了size和modCount屬性,但是Itr中的這cursor、expectedModCount卻沒有發生變化,當增強for循環再次執行的時候,調用的卻是Itr中的方法,最終發現了數據不一致。這就是本例ConcurrentModificationException產生的根本原因。
3.解決方案
最保險的方案就是在遍歷的時候不remove,最後再remove…
@Test
public void test2() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List<Integer> tmp = new ArrayList<>();
for(int num: list) {
if (num == 2) {
tmp.add(num);
}
}
list.removeAll(tmp);
System.out.println(StringUtils.join(list, ","));
}