数据 List dataList = new ArrayList();
1、for循环
我们一般可以见到类似如下的遍历方式
for(int i=0;i <dataList.size();i++){
dataList.get(i);
}
这样的遍历一般边遍历边往列表里面加item可以往i以后加,不能往i以前加,否则加入的item就漏遍历了,而且i位置的item会遍历两遍。
比如列表[1,2,3,4] 当i=1的时候,dataList.get(i)是2,插入5便是[1,5,2,3,4],下一次i是2,dataList.get(i)还是2。
删除操作也是能删除i以后,不能删除i及i以前的item。
比如 列表 [1,2,3,4],如果遍历到i=1的时候删除了dataList.get(i)=2,那么列表就变成 [1,3,4],长度为3,i已经等于1了,下一次i加1取列表item,i就是2,dataList.get(i)就是4了。会漏遍历item值为3的item,所以边遍历边删除会有遍历不完整的问题。
所以总结为:for循环遍历,如果要边遍历边删除或者增加,那么只能把数据添加到当前还没有遍历到的位置。
2.Iterator迭代器遍历
Iterator<Integer> iterable= dataList.iterator();
while (iterable.hasNext()){
int a = iterable.next();
}
我们来看一下源码的iterator到底是什么
ArrayList的iterator是
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
protected int limit = ArrayList.this.size;
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor < limit;
}
public E next() {
if (modCount != expectedModCount)//检查迭代器记录的变更次数是否和ArrayList记录的变更次数一样,否则抛异常。也就是说遍历的时候除了迭代器,谁也不能更改列表(调用add或者remove),否则下次调用next就抛异常
throw new ConcurrentModificationException();
int i = cursor;
if (i >= limit)
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();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
try {//迭代器自己可以调用remove,调用完会同步更改次数
ArrayList.this.remove(lastRet);
cursor = lastRet;//移除后接着遍历移除位置的下一个数据
lastRet = -1;
expectedModCount = modCount;//同步更改次数
limit--;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
可以看出 ArrayList用Iterator遍历的话,也只能用Iterator移除才行,调用Iterator移除是安全的,不会漏遍历也不会多遍历。不能添加也不能通过ArrayList对象自己移除或者添加,否则抛出异常。
全局列表多处访问或者多线程访问的时候尤其要注意,用Iterator遍历是很危险的事情,要做好同步锁和添加移除控制。
3.foreach遍历
for (int r : dataList) {
}
foreach的底层实现可以参考 肥肥技术宅 大佬的博客(foreach 循环的底层原理及正确使用方式,一定要掌握这些!_foreach底层_肥肥技术宅的博客-优快云博客)
大概的意思就是 foreach是个语法糖,在编译阶段就会被转译。
数组类型列表遍历会执行
for(int i=0;i <size;i++)
集合类型列表遍历会执行
Iterator<Integer> iterable= dataList.iterator();
while (iterable.hasNext()){
int a = iterable.next();
}
转来转去其实只有两种遍历,foreach只是为了简化代码书写。
Java中遍历ArrayList的正确方式与注意事项

文章详细介绍了在Java中遍历ArrayList的三种常见方式:for循环、Iterator迭代器和foreach,并分析了每种方式在边遍历边修改列表时的潜在问题。for循环可能引发漏遍历或重复遍历,Iterator允许安全删除但不允许添加,而foreach实际上是Iterator的语法糖。在多线程或并发环境下,需要注意遍历过程中的同步控制。
2929

被折叠的 条评论
为什么被折叠?



