前言:
现时小伙伴们对“java循环删除元素”都比较关切,兄弟们都想要知道一些“java循环删除元素”的相关资讯。那么小编也在网上收集了一些有关“java循环删除元素””的相关资讯,希望姐妹们能喜欢,兄弟们快快来了解一下吧!Alibaba Java开发手册中指出,不要在 foreach 循环里进行元素的 remove/add 操作,那么进行这些操作到底会产生什么样的结果呢?
我们先来写个实例看看。
public class TestForeach { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); numbers.add(1); numbers.add(2); numbers.add(3); for (Integer number : numbers) { numbers.remove(number); } } }
再来看看执行结果:
根据报错提示,可以定位到报错的位置在java.util.ArrayList$Itr.next(ArrayList.java:997),并最终定位到java.util.ArrayList$Itr.checkForComodification()那么我们跳转过去看看源码。
可以看到,我们定位到了ArrayList中内部类Itr类中的next()方法,类Itr实现了迭代器接口Iterator,因此可以用来遍历集合的元素。
那么为什么我们使用增强for循环时,会进入到迭代器的next()方法中呢?我们来看看反编译后的class文件,揭开其真实面目。
原来,源代码在编译之后,实际上是使用迭代器来帮我们进行遍历的,这就足以说明为什么产生报错的地方是在Itr的next()方法处了。接下来我们再来查看next()方法。
果然,在方法的第一行处执行了,checkForComodification(),也就是最终报错的地方,从方法名可以大概知道,该方法的目的是检测集合是否被修改过。我们再跟进看看:
发现方法中就是在判断两个类变量值是否相等,那么这两个变量又来自何处,我们继续跟进源码:
从上面两张图可以得知,modCount来自AbstractList类,而ArrayList继承自AbstractList,因此可以直接使用该变量,该字段的注释的表明,该字段记录了集合结构被修改的次数,而迭代器被创建的时候将该字段赋值给了expectedModCount字段,这使得一开始它们的值是相等的。
这里猜测,我们在对集合元素进行删除操作时,修改了modCount的值,从而导致两个变量的值不相等,我们来一探究竟。
public E remove(int index) { Objects.checkIndex(index, size); final Object[] es = elementData; @SuppressWarnings("unchecked") E oldValue = (E) es[index]; fastRemove(es, index); return oldValue; }
private void fastRemove(Object[] es, int i) { modCount++; final int newSize; if ((newSize = size - 1) > i) System.arraycopy(es, i + 1, es, i, newSize - i); es[size = newSize] = null; }
最终在fastRemove()执行了modCount++操作,因此而导致了抛出ConcurrentModificationException。
那么在遍历集合时,我们正确的删除姿势是什么样的呢?
public class TestForeach { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); numbers.add(1); numbers.add(2); numbers.add(3); Iterator<Integer> iterator = numbers.iterator(); while (iterator.hasNext()) { iterator.next(); iterator.remove(); } } }
正确的姿势就是使用迭代器的remove()方法。
public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
在该方法中,执行了expectedModCount = modCount;操作,从而避免了ConcurrentModificationException异常。
标签: #java循环删除元素