概念
java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。
Iterator接口和Collection接口有什么关系??
- java.util.Collection接口继承Iterator接口,因此所有实现Collection接口的实现类都可以使用该迭代器对象。
方法
方法声明 | 功能介绍 |
---|---|
boolean hasNext() |
判断集合中是否有可以迭代/访问的元素 |
E next() |
用于取出一个元素并指向下一个元素 |
void remove() |
用于删除访问到的最后一个元素 |
迭代打印集合
public class CollectionPrint {
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("hello");
c1.add(66);
//直接调用toString方法,对应的c1就是一个字符串打印出来 String类型的整体
System.out.println("c1:"+c1);//[hello, 66]
//第二种:用迭代器判断打印
//2.遍历方式二:使用迭代器来遍历集合中的所有元素 更加灵活
// 获取当前集合中的迭代器对象
Iterator iterator = c1.iterator();
// 判断是否有元素可以访问
System.out.println(iterator.hasNext());//true
// 取出下一个
System.out.println(iterator.next());//hello
// 判断是否有元素可以访问
System.out.println(iterator.hasNext());//true
// 取出下一个
System.out.println(iterator.next());//66
// 判断是否有元素可以访问
System.out.println(iterator.hasNext());//false
// 取出下一个
//编译OK,运行发生NoSuchElementException 没有元素异常
System.out.println(iterator.next());//NoSuchElementException
}
}
- while循环替换:
while (iterator.hasNext()){
System.out.println(iterator.next());
}
案例
- 如何使用迭代器实现toString方法的打印效果?
上个循环已经使得迭代器走到了最后,因此需要重置迭代器
System.out.println(c1);
// 由于上个循环已经使得迭代器走到了最后,因此需要重置迭代器
iterator = c1.iterator();
StringBuilder s = new StringBuilder();
s.append("[");
while (iterator.hasNext()){
Object next = iterator.next();
if(!iterator.hasNext()){
s.append(next).append("]");
}else {
// 否则拼接元素加逗号加空格
s.append(next).append(",").append(" ");
}
}
System.out.println(s);
里面的if对应的指针再次往下,去看是否有下一个元素,如果没有则就是最后一个元素
迭代删除元素
- 迭代删除元素为66
// 由于上个循环已经使得迭代器走到了最后,因此需要重置迭代器
iterator = c1.iterator();
//[hello, 66, Person{name='zhangfei', age=30}]
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println();
if(next.equals(66)){
//使用迭代器remove方法删除元素
iterator.remove();
}
}
System.out.println("迭代器删除元素后:"+c1);//[hello, Person{name='zhangfei', age=30}]
- 如果在remove 时候使用集合的remove方法会发生什么?
// 由于上个循环已经使得迭代器走到了最后,因此需要重置迭代器
iterator = c1.iterator();
Person zhangfei = new Person("zhangfei", 30);
Integer d = 66;
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(d.equals(next));
if(d.equals(next)){
c1.remove(next);
}
}
System.out.println("迭代器删除元素后:"+c1);//[hello, Person{name='zhangfei', age=30}]
}
- 编译发现是通过的,但是运行的时候会出现:ConcurrentModificationException报错
- 并发修改异常
迭代一个集合的时候不允许去修改这个集合,如果修改,对应迭代结果是不确定的。
比如说,在班级里面我来数一下咱们班有多少个人,这个时候我正在数「其实就是迭代的过程」,但是这个时候班里面的人进进出出大量的人进进出出,会不会影响你数数。所以这个情况下迭代的结果就是不确定的,
如果检测到这个行为就抛出异常。就像我睡不着了就开始数羊,一只羊、两只羊,然后这个时候有人给你来个电话,你是不是挂了电话就忘了自己数到了哪里了。
所以迭代器的hasNext就相当于在数一只羊一只羊,然后我再数的时候前面的羊没了「c1.remove相当于把我的羊弄没了」,它是不是就把我们迭代器破坏了可以看到下面ArrayList里面的hasNext源码,在c1.remove完成了以后,对应的cursor=2,size=2,这个时候hasNext返回的是false,不会进入下一个循环,直接去打印了集合c1
public boolean hasNext() {
return cursor != size;
}
所以在迭代器里面,自己迭代自己删除。不能让外面的对象过来操作我们的迭代内容。只要不是在迭代的过程中,用集合的remove方法是没有问题的。
总结:
- 在迭代过程中不能对集合/数组对象进行操作,否则会报并发修改异常。
- 更加灵活,但是没有toString洒脱,调用的方法比较多