这个问题看似好像挺简单挺幼稚的,然而就这个幼稚的问题还曾经困扰过我一阵呢,其实犯这个错误的根本缘由是咱们对于基础知识的理解和掌握上还有不足的表现,基本功有些人老是以为不重要,认为更多的扩大学习的广度才是最重要的,我认为这是很容易犯的,同时也是很致命的错误观点!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--; } }
我想你编程时间长了,也会偶尔遇到这些相似简单却让你头疼的问题,遇到这些问题首先检查下本身的逻辑是否有问题,若是逻辑没有问题就检查下代码的结构是否有问题吧,这就是所谓的基本功,之后我也会慢慢的增强巩固本身基本功方面的能力,一块儿加油吧。