我是靠谱客的博主 柔弱冷风,最近开发中收集的这篇文章主要介绍遍历ArrayList时如何正确移除一个元素,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

错误写法示例一:
public static void remove ( ArrayList < String > list ) {
for ( int i = 0 ; i < list . size (); i ++ ) {
String s = list . get ( i );
if ( s . equals ( "bb" )) {
list . remove ( s );
}
}
}
错误写法示例二:
public static void remove ( ArrayList < String > list ) {
for ( String s : list ) {
if ( s . equals ( "bb" )) {
list . remove ( s );
}
}
}
要分析产生上述错误现象的原因唯有翻一翻 jdk ArrayList 源码,先看下 ArrayList 中的 remove 方法(注
ArrayList 中的 remove 有两个同名方法,只是入参不同,这里看的是入参为 Object remove 方法)是
怎么实现的:
public boolean remove ( Object o ) {
if ( o == null ) {
for ( int index = 0 ; index < size ; index ++ )
if ( elementData [ index ] == null ) {
fastRemove ( index );
return true ;
}
} else {
for ( int index = 0 ; index < size ; index ++ )
if ( o . equals ( elementData [ index ])) {
fastRemove ( index );
return true ;
}
}
return false ;
}
按一般执行路径会走到 else 路径下最终调用 faseRemove 方法:
private void fastRemove ( int index ) {
modCount ++ ;
int numMoved = size - index - 1 ;
if ( numMoved > 0 )
System . arraycopy ( elementData , index + 1 , elementData , index ,
numMoved );
elementData [ -- size ] = null ; // Let gc do its work
}
可以看到会执行 System.arraycopy 方法,导致删除元素时涉及到数组元素的移动。针对错误写法一,在
遍历第二个元素字符串 bb 时因为符合删除条件,所以将该元素从数组中删除,并且将后一个元素移动
(也是字符串 bb )至当前位置,导致下一次循环遍历时后一个字符串 bb 并没有遍历到,所以无法删除。
针对这种情况可以倒序删除的方式来避免:
public static void remove ( ArrayList < String > list ) {
for ( int i = list . size () - 1 ; i >= 0 ; i -- ) {
String s = list . get ( i );
if ( s . equals ( "bb" )) {
list . remove ( s );
}
}
}
因为数组倒序遍历时即使发生元素删除也不影响后序元素遍历。
而错误二产生的原因却是 foreach 写法是对实际的 Iterable hasNext next 方法的简写,问题同样处在
上文的 fastRemove 方法中,可以看到第一行把 modCount 变量的值加一,但在 ArrayList 返回的迭代器
(该代码在其父类 AbstractList 中):
public Iterator < E > iterator () {
return new Itr ();
}
这里返回的是 AbstractList 类内部的迭代器实现 private class Itr implements Iterator ,看这个类的 next
方法:
public E next () {
checkForComodification ();
try {
E next = get ( cursor );
lastRet = cursor ++ ;
return next ;
} catch ( IndexOutOfBoundsException e ) {
checkForComodification ();
throw new NoSuchElementException ();
}
}
第一行 checkForComodification 方法:
final void checkForComodification () {
if ( modCount != expectedModCount )
throw new ConcurrentModificationException ();
}
这里会做迭代器内部修改次数检查,因为上面的 remove(Object) 方法把修改了 modCount 的值,所以才
会报出并发修改异常。要避免这种情况的出现则在使用迭代器迭代时(显示或 foreach 的隐式)不要使用
ArrayList remove ,改为用 Iterator remove 即可。
public static void remove ( ArrayList < String > list ) {
Iterator < String > it = list . iterator ();
while ( it . hasNext ()) {
String s = it . next ();
if ( s . equals ( "bb" )) {
it . remove ();
}
}
}

最后

以上就是柔弱冷风为你收集整理的遍历ArrayList时如何正确移除一个元素的全部内容,希望文章能够帮你解决遍历ArrayList时如何正确移除一个元素所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部