<老马说编程>中讲过ArrayList,先去看一下
动态删除ArrayList中的元素
ArrayList删除元素后长度变小了,元素的索引也会跟着改变,但是迭代的下标没有跟着相应的改变。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Created with IDEA by penelopeWu
* Date:2017/9/22 9:18
*/
public class SafeOptrationOfArrayList {
public static void main(String[] args) {
List<String> list = new ArrayList();
/*
list.add("c");
list.add("a");
list.add("c");
list.add("b");
list.add("c");
list.add("d");
list.add("c");
*/
list.add("a");
list.add("c");
list.add("c");
list.add("b");
list.add("c");
list.add("c");
list.add("d");
list.add("c");
}
/**
* 删除Arraylist中值为"c"的元素
* 不安全
* @param list
*/
public static void removeListElement1(List<String> list) {
for (int i = 0; i < list.size(); i++) {
if ("c".equals(list.get(i))) {
list.remove(i);
}
}
}
/**
* 删除Arraylist中值为"c"的元素
* 安全
* @param list
*/
public static void removeListElement2(List<String> list) {
for (int i = 0; i < list.size(); i++) {
if ("c".equals(list.get(i))) {
list.remove(i);
--i;//删除元素的同时,要让迭代下标也跟着改变
}
}
}
/**
* 删除Arraylist中值为"c"的元素
* 安全
* @param list
*/
public static void removeListElement3(List<String> list) {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String str = iterator.next();
if ("c".equals(str)){
iterator.remove(); //为什么iterator的remove方法是可靠的?
}
}
}
}
ArrayList.remove(int index)源码
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1; //需要移动的元素个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); //数组复制,被删除元素之后的元素各前移一位
elementData[--size] = null; // clear to let GC do its work // 空出的位置 设置为null。
return oldValue; //返回被删除的元素
}
System.arraycopy(...)
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
迭代器操作ArrayList为什么是可靠的?
先看下ArrayList的内部类Itr的源码
/**
* An optimized version of AbstractList.Itr
*/
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; //敲黑板!!,将ArrayList的modCount赋值给Itr的expectedModCount,expectedModCount接下来有大用处
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification(); //首先检查ArrayList是否被结构性修改
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();//首先检查ArrayList是否被结构性修改
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() { //敲黑板!!如果ArrayList被结构性修改,这时modCount和expectedModCount就不再一致了,直接抛异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}