项目场景:
笔试遇到了一个看似很简单的题目:
一个ArrayList集合有四个整数元素,要求删除掉其中大于10的元素。
问题描述
看到这个题目,脑子一激灵,这还不简单?直接写下以下代码:
List<Integer> list = new ArrayList<Integer>(); list.add(6); list.add(12); list.add(2); list.add(8); for(Integer i:list){ if(i>10){ list.remove(i); } } System.out.println(list);
然后果断就悲剧了,运行结果如下:
由此可见这样写是不允许的,我这道题应该是悲剧了,想想也是,怎么可能这么简单。
原因分析:
ArrayList的父类AbstarctList中有一个域modCount,每次对集合进行修改(增添、删除元素)时modCount都会+1。
对于集合而言,增强for循环的实现原理就是迭代器Iterator,在这里,迭代ArrayList的Iterator中有一个变量expectedModCount,该变量会初始化和modCount相等,但当对集合进行插入,删除操作,modCount会改变,就会造成expectedModCount!=modCount,此时就会抛出java.util.ConcurrentModificationException异常,是在checkForComodification方法中,代码如下:
private void checkForComodification(int expectedModCount) { if (this.modCount != expectedModCount) { throw new ConcurrentModificationException(); } }
解决方案:
1.在使用迭代器遍历时,可使用迭代器的remove方法,因为Iterator的remove方法中 有如下的操作:
expectedModCount = modCount;
所以避免了ConcurrentModificationException的异常。
List<Integer> list = new ArrayList<Integer>(); list.add(6); list.add(12); list.add(2); list.add(8); Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()){ Integer i =iterator.next(); if(i>10){ iterator.remove(); } } System.out.println(list);
2.采用普通for循环,通过索引的方式删除元素,需要注意的是我这里采用的是倒序遍历,如果正序遍历的话要注意索引的变化
List<Integer> list = new ArrayList<Integer>(); list.add(6); list.add(12); list.add(2); list.add(8); for (int i = 0; i < list.size(); i++) { Integer num = list.get(list.size() - 1 - i); if(num>10) { list.remove(list.size() - 1 - i); } } System.out.println(list);
以上两种方法都可以正常输出结果: