搬砖系列如何在遍历List时安全删除集合元素

Posted christmad

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搬砖系列如何在遍历List时安全删除集合元素相关的知识,希望对你有一定的参考价值。

 

技术分享图片
 1 public void testIterRemove() {
 2         List l1 = new ArrayList(Arrays.asList(1, 2, 3, 4, 5));
 3         Iterator<Integer> iterator = l1.iterator();
 4         System.out.println("before=" + l1);
 5         while (iterator.hasNext()) {
 6             iterator.next();
 7             iterator.remove();
 8         }
 9         System.out.println("after=" + l1);
10 }
11 /*
12 before=[1, 2, 3, 4, 5]
13 after=[]
14 */
遍历时移除元素的正确示例

代码中关键的部分在于:

iterator.next();

iterator.remove();

二者缺一不可。当然调用next()之前要调用hasNext()确保没有越界。

简单分析两个方法的代码即可得出答案:

首先看remove()方法,为什么hasNext() + remove()不可以呢:

技术分享图片
 1         public void remove() {
 2             if (lastRet < 0)
 3                 throw new IllegalStateException();
 4             checkForComodification();
 5 
 6             try {
 7                 ArrayList.this.remove(lastRet);
 8                 cursor = lastRet;
 9                 lastRet = -1;
10                 expectedModCount = modCount;
11             } catch (IndexOutOfBoundsException ex) {
12                 throw new ConcurrentModificationException();
13             }
14         }
ArrayList#Itr.remove()

由于代码用属性lastRet(即lastReturn index)控制异常,所以查看ArrayList#Itr的实例初始化语句,lastRet初值是-1,如果单独调用remove()会报错。

再看一下next()方法,就会找出答案:

技术分享图片
 1         public E next() {
 2             checkForComodification();
 3             int i = cursor;
 4             if (i >= size)
 5                 throw new NoSuchElementException();
 6             Object[] elementData = ArrayList.this.elementData;
 7             if (i >= elementData.length)
 8                 throw new ConcurrentModificationException();
 9             cursor = i + 1;
10             return (E) elementData[lastRet = i];
11         }
ArrayList#Itr.next()

在方法中首先将cursor记录到变量 i,返回前将 i 的知赋给 lastRet ,完成lastRet的更新。方法返回值不是本次要考虑的范畴。

再回过头看remove()方法,有了lastRet后,就可以重置cursor。在方法中调用了ArrayList#remove(),这个方法会重新调整数组元素的位置,如果删掉的不是最后一个位置的元素(numMoved == 0 表示删掉的正好是最后一位元素),将会把index后面的元素往前移动一个,最后将elementData[--size] = null 为移除旧元素,帮助GC。

 

总结:

需要先调用next()更新lastRet的值,才能在remove()中通过第一关对lastRet的检查。因此在遍历List时需要联合使用 :

while( it.hasNext() ) 
{ 
    it.next(); 
    it.remove();
} 

 

以上是关于搬砖系列如何在遍历List时安全删除集合元素的主要内容,如果未能解决你的问题,请参考以下文章

集合系列日记(17.5.13)

Kotlin集合操作总结 ( List 集合 | MutableList 集合 | List 集合遍历 | Set 集合 | MutableSet 集合 | Map 集合 | 可变 Map集合 )

Kotlin集合操作总结 ( List 集合 | MutableList 集合 | List 集合遍历 | Set 集合 | MutableSet 集合 | Map 集合 | 可变 Map集合 )

集合元素如何添加?如何删除?如何遍历?

HashMap和List遍历方法总结及如何遍历删除

java集合基础