目录
遍历的3种方式
1,迭代器循环
2,增强for循环
3,普通for循环
方式1:迭代器循环
迭代器创建后,最好立即使用,不然之后对集合进行的增删改操作会导致迭代器遍历报错
原因:
1,系统创建迭代器时,会初始化 字段 expectedModCount = modCount,迭代器遍历获取字段时,next()会先对该字段进行校验
2, 对集合进行的 任何增删 操作都会导致 modCount++,从而在迭代器遍历时,在expectedModCount == modCount 中返回false,导致报错
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; //初始化 expectedModCount 字段
public E next() {
//获取下个元素时 , 会先对字段 expectedModCount == modCount 进行校验
checkForComodification();
....
}
final void checkForComodification() {
if (modCount != expectedModCount) // 不相等,会报错
throw new ConcurrentModificationException();
}
}
Iterator迭代器
功能:
1,单向遍历
2,遍历过程中,不能增加和修改元素
3,遍历过程中,只能使用 Iterator提供的remove() 删除元素,不能使用Collection.remove() 删除元素
注意事项:
删除元素前,需要先调用next(),否则会报错
因为remove()中,更新 lastRet=-1,而要调用remove(),会先校验lastRet<0,抛异常
范例:
Collection<Student> c = new ArrayList<Student>();
Student s1 = new Student("zhang", 12);
Student s2 = new Student("lsii", 23);
Student s3 = new Student("wangwu", 24);
Student s4 = new Student("zhoaliu", 24);
c.add(s1);
c.add(s2);
c.add(s3);
c.add(s4);
Iterator<Student> itStu = c.iterator();
while (itStu.hasNext()) {
Student s = itStu.next();
if (s.getName() == "lisi") {
// c.remove(s1); 会报错
itStu.remove(); //删除遍历得到的元素
}
System.out.println(s);
}
System.out.println(c);
方法:
hasNext() 是否还有下一个元素:通过cursor字段,判断是否到达集合边界
next() 先让游标后移一位,再返回索引元素
remove() 删除元素
public E next() {
checkForComodification();
int i = cursor;
...
Object[] elementData = ArrayList.this.elementData;
...
cursor = i + 1;
return (E) elementData[lastRet = i];
}
//不能直接调用,remove前需要调用next(),因为本方法中 lastRet字段
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1; //更新 lastRet
expectedModCount = modCount; //执行完 remove后,更新 expectedModCount
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
ListIterator迭代器
描述: 弥补了Iterator迭代过程中,不能增加元素
功能:
1,双向遍历
2,遍历过程中,可以使用迭代器方法,增删改集合元素
注意:
1,删除元素前,必须调用next(),否则会报错
因为remove()中,更新 lastRet=-1,而要调用remove(),会先校验lastRet<0,抛异常
2,下面代码中,如果没有调用next(),只是单纯的add(), 会导致死循环,直到内存溢出,引发错误
解决方案:
add() 和 next() 一起使用
范例:
ArrayList<Student> c = new ArrayList<Student>();
Student s1 = new Student("zhang", 12);
Student s2 = new Student("lsii", 23);
Student s3 = new Student("wangwu", 24);
Student s4 = new Student("zhoaliu", 24);
c.add(s1);
c.add(s2);
c.add(s3);
c.add(s4);
ListIterator<Student> listIterator = c.listIterator();
while(listIterator.hasNext()){
listIterator.add(s3);
// listIterator.remove(); //直接删除会报错,需要先获取,再删除,
//因为remove()后,更新 lastRet=-1
Student next = listIterator.next();
System.out.println(next);
}
方法:
hasNext() 是否还有下一个元素:通过cursor字段,判断是否到达集合边界
继承自Iterator
next() 返回下一个元素,继承自Iterator
hasPrevious 是否还有上一个元素
previous() 返回上一个元素
add () 增加元素
remove() 删除元素,继承自Iterator
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
int i = cursor - 1;
...
Object[] elementData = ArrayList.this.elementData;
...
cursor = i;
return (E) elementData[lastRet = i];
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1; //更新 lastRet
expectedModCount = modCount; //执行完add后,更新 expectedModCount
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
方式2:增强for循环
Collection<String> strC = new ArrayList<String>();
strC.add("fa");
strC.add("");
strC.add("");
strC.add("");
strC.add("ffdasfa");
for (String s : strC) {
System.out.println(s);
}
底层实现:
增强for循环,运行的时候,编译器为其生成1个Iterator迭代器,调用iterator的hasNext(),next()方法进行遍历
缺点: 和iterator迭代器一样,只读
1,只能单向遍历
2,遍历时,不能 向集合中 增加和修改元素,不能删除元素
方式3:普通for循环
优势:可以在 遍历集合的同时,对集合元素进行增删改