您的位置:首页 > 其它

如何安全操作ArrayList?

2017-09-22 00:00 197 查看
摘要: 又是被面试官问到的问题。

<老马说编程>中讲过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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: