在使用ArrayList、LinkedList过程中,经常需要查找到其中某个元素,然后将该元素从列表中删除。最优雅的方式如下。
使用Iterator方式
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(Integer.toString(i));
}
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String str = iterator.next();
if (str.equals("1")) {//删除值为1的元素
iterator.remove();
}
}
除了上述的方式,还有其他的方式,但是都可能存在某些问题,需要慎用。
使用for(int i = 0; i < list.size(); i++)方式
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(Integer.toString(i));
}
System.out.println("list 元素个数:" + list.size());
// list 元素个数:10
int j = 0; //用来记录遍历元素的个数
for (int i = 0; i < list.size(); i++) {
j++;
if ("1".equals(list.get(i))) {
list.remove("1");
}
}
System.out.println("遍历到的元素个数为:" + j);
// 遍历到的元素个数为:9,少遍历了一个元素
发现并没有遍历所有的元素,因为list.remove后,导致列表元素个数和位置发生变化。
使用for(String s: list)增强的for循环方式
这种方式遍历时候,会抛出ConcurrentModificationException异常
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(Integer.toString(i));
}
for (String s: list) {
if ("1".equals(s)) {
list.remove(s);
}
}
先看看增强for循环编译后代码内容
List<String> list = new ArrayList();
for(int i = 0; i < 10; ++i) {
list.add(Integer.toString(i));
}
Iterator var4 = list.iterator();
while(var4.hasNext()) {
String s = (String)var4.next();
if ("1".equals(s)) {
list.remove(s);
}
}
实际上,增强的for循环也是用迭代器来实现的,这种方式与最上面方式的区别在于,删除的语句。
- 一个使用的是iterator.remove()
- 一个使用的是list.remove(s)
其实在iterator.remove()的源码种,iterator.remove()也是调用了list.remove(s)方法
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
expectedModCount:iterator对象中用来记录list对象修改的次数
modCount:list对象中用来记录list对象修改的次数
-
调用iterator.remove()时,expectedModCount和modCount都修改了;
-
而直接调用list.remove(s)只修改modCount,expectedModCount没有修改,在下一次调用iterator.next()会检查这两个属性是否相等,如果不相等就会抛出ConcurrentModificationException异常。
网友评论