Bootstrap

java for 删除元素_Java中使用for循环删除集合中元素需要注意的点

删除集合中的元素,第一反应是遍历集合,比较找到相应的元素然后删除。遍历集合最容易想到的是for循环。

删除集合中为3的元素:

1 List list = new ArrayList();2 for(int i = 0;i<10;i++){3 list.add(i);4 }5 for(int i = 0;i<10;i++){6 list.add(i);7 }8 System.out.println("删除前"+list);9 System.out.println("size:"+list.size());10 for(int i = 0;i

运行结果:

删除前[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

size:20

删除后[0, 1, 2, 4, 5, 6, 7, 8, 9, 0, 1, 2, 4, 5, 6, 7, 8, 9]

size:18

看起来一点问题也没有,那么我们把集合中元素的顺序换一下。

1 List list = new ArrayList();2 for(int i = 0;i<10;i++){3 list.add(i);4 list.add(i);5 }6 System.out.println("删除前"+list);7 System.out.println("size:"+list.size());8 for(int i = 0;i

运行结果:

删除前[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]

size:20删除后[0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]

size:19

问题出现了,当删除相邻两个重复元素的时候,只删除一个,这是什么原因呢?

ArrayList的底层结构是数组类型,数组的特点是删除某个元素时,后面所有元素的索引都会往前移,而此时for循环的指针是却是向下移动的。

008664c19451eef98550aadf15a2e652.png

解决方案一:使用每次删除元素的时候,将for循环指针回调一次

1 List list = new ArrayList();2 for(int i = 0;i<10;i++){3 list.add(i);4 list.add(i);5 }6 System.out.println("删除前"+list);7 System.out.println("size:"+list.size());8 for(int i = 0;i

运行结果:

删除前[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]

size:20删除后[0, 0, 1, 1, 2, 2, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]

size:18

解决方案二:使用迭代器

1 List list = new ArrayList();2 for(int i = 0;i<10;i++){3 list.add(i);4 list.add(i);5 }6 System.out.println("删除前"+list);7 System.out.println("size:"+list.size());8 Iterator it =list.iterator();9 while(it.hasNext()){10 if(3==it.next()){11 it.remove();12 }13 }14 System.out.println("删除后"+list);15 System.out.println("size:"+list.size());

运行结果:

删除前[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]

size:20删除后[0, 0, 1, 1, 2, 2, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]

size:18

为什么使用迭代器可以实现这样的操作呢?下面将基于ArrayList的Iterator的实现分析Iterator的原理。

在ArrayList类中有个方法iterator(),此方法将返回一个iterator的实现,这里可以看出实现类叫Itr,通过其它源码可知,此类是AarryList的内部类,即ArryList的Iterator实现在ArrayList内部

1 public Iteratoriterator() {2 return newItr();3 }

ArrayList中实现类Itr类的源码:

1 private class Itr implements Iterator{2 /**

3 * 下一个返回的位置4 */

5 int cursor = 0;6

7 /**

8 * 当前操作的位置9 */

10 int lastRet = -1;11

12 /**

13 * 类似版本号,检查List是否有更新14 */

15 int expectedModCount =modCount;16

17 public boolean hasNext() { //判断是否有下一个元素

18 return cursor !=size();19 }20

21 public E next() { //返回下一个元素

22 checkForComodification();23 try{24 int i = cursor; //cursor记录的是下一个元素,所以调用next时将返回的是cursor对应的元素

25 E next = get(i); //记录需要返回的元素

26 lastRet = i; //记录当前元素

27 cursor = i + 1; //记录下一个元素

28 returnnext;29 } catch(IndexOutOfBoundsException e) {30 checkForComodification();31 throw newNoSuchElementException();32 }33 }34

35 public void remove() { //移除元素

36 if (lastRet < 0)37 throw newIllegalStateException();38 checkForComodification(); //检查是否有更改,remove或者add

39

40 try{41 AbstractList.this.remove(lastRet); //删除当前元素

42 if (lastRet < cursor) //删除了之后指标减1

43 cursor--;44 lastRet = -1;45 expectedModCount = modCount; //保持版本号一致

46 } catch(IndexOutOfBoundsException e) {47 throw newConcurrentModificationException();48 }49 }50

51 final void checkForComodification() { //如果有更改则抛出ConcurrentModificationException异常

52 if (modCount !=expectedModCount)53 throw newConcurrentModificationException();54 }55 }

在next()方法中可以看到,通过移动cursor游标来指向集合下一个元素。

再看remove()方法,代码的43行,删除当前元素后,游标前移了。

结论:这两种方法,基本思想都是将指针回调。

;