迭代器和增强for循环

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器和增强for循环相关的知识,希望对你有一定的参考价值。

Iterator迭代器的使用:

迭代:Iterator,即collection集合元素的通用获取方式

java.util.Iterator接口。迭代器(对集合进行遍历)

有两个常用的方法

Boolean hasNext()如果仍有元素可以迭代,则返回true
判断集合中还有没有下一个元素,有就返回true,没有就返回false
E next()返回迭代的下一个元素
取出集合中的下一个元素

Iterator迭代器,是一个接口,我们无法直接使用,需要Iterator接口的实现类对象,获取实现类的方式比较特殊
Collection接口中有一个方法,叫Iterator(),这个方法返回的就是迭代器的实现类对象
Iterator iterator()返回在此collection的元素上进行迭代的迭代器

迭代器的使用步骤(重点)
1、使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
3、使用Iterator接口中的方法next取出集合中的下一个元素

package Iterator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo01Collection {

    public static void main(String[] args) {
        //创建一个集合对象
        Collection<String> coll=new ArrayList<>();
        coll.add("星星");
        coll.add("仰望星空");
        coll.add("最美的太阳");
        coll.add("这就是爱");
        //1、使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
        //Iterator<E>的接口也是有泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型

        //多态     接口          实现类对象
        Iterator<String>  it=coll.iterator();

        //发现使用迭代器取出集合中元素的代码是一个重复的过程
        //所以我们可以使用循环优化
        //不知道集合中有多少元素,使用while集合
        //循环结束的条件,hasNext方法返回false
        while (it.hasNext()){
            String e=it.next();
            System.out.println(e);
        }

//        //2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
//        boolean b=it.hasNext();
//        System.out.println(b);//true
//
//       // 3、使用Iterator接口中的方法next取出集合中的下一个元素
//        String s=it.next();
//        System.out.println(s);
//
//        //2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
//        b=it.hasNext();
//        System.out.println(b);//true
//        // 3、使用Iterator接口中的方法next取出集合中的下一个元素
//        s=it.next();
//        System.out.println(s);
//        2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
//        b=it.hasNext();
//        System.out.println(b);//true
//        // 3、使用Iterator接口中的方法next取出集合中的下一个元素
//        s=it.next();
//        System.out.println(s);
//        2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
//        b=it.hasNext();
//        System.out.println(b);//true
//        // 3、使用Iterator接口中的方法next取出集合中的下一个元素
//        s=it.next();
//        System.out.println(s);
//        
//          b=it.hasNext();
        System.out.println(b);没有元素,返回false
        // 3、使用Iterator接口中的方法next取出集合中的下一个元素
        s=it.next();没有元素,在取出元素会抛出NoSuchElementException没有元素异常
        System.out.println(s);
    }
}

Iterator(迭代器)实现原理

这里我们来看看Java里AbstractList实现Iterator的源代码:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { // List接口实现了Collection<E>, Iterable<E> 

    protected AbstractList() {  
    }     
    public Iterator<E> iterator() {  
    return new Itr();  // 这里返回一个迭代器    }  

    private class Itr implements Iterator<E> {  // 内部类Itr实现迭代器

    int cursor = 0;  
    int lastRet = -1;  
    int expectedModCount = modCount;  

    public boolean hasNext() {  // 实现hasNext方法
            return cursor != size();  
    }  

    public E next() {  // 实现next方法
            checkForComodification();  
        try {  
        E next = get(cursor);  
        lastRet = cursor++;  
        return next;  
        } catch (IndexOutOfBoundsException e) {  
        checkForComodification();  
        throw new NoSuchElementException();  
        }  
    }  

    public void remove() {  // 实现remove方法
        if (lastRet == -1)  
        throw new IllegalStateException();  
            checkForComodification();  

        try {  
        AbstractList.this.remove(lastRet);  
        if (lastRet < cursor)  
            cursor--;  
        lastRet = -1;  
        expectedModCount = modCount;  
        } catch (IndexOutOfBoundsException e) {  
        throw new ConcurrentModificationException();  
        }  
    }   
    final void checkForComodification() {  
        if (modCount != expectedModCount)  
        throw new ConcurrentModificationException();  
    }  
    }  
}

可以看到,实现next()是通过get(cursor),然后cursor++,通过这样实现遍历。

这部分代码不难看懂,唯一难懂的是remove操作里涉及到的expectedModCount = modCount;

在网上查到说这是集合迭代中的一种“快速失败”机制,这种机制提供迭代过程中集合的安全性。

从源代码里可以看到增删操作都会使modCount++,通过和expectedModCount的对比,迭代器可以快速的知道迭代过程中是否存在list.add()类似的操作,存在的话快速失败!
在第一个例子基础上添加一条语句:

import java.util.*;
public class Muster {

    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        Iterator it = list.iterator();
        while(it.hasNext()){
            String str = (String) it.next();
            System.out.println(str);
            list.add("s");        //添加一个add方法
        }
    }
}

运行结果:

a
Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
  at java.util.ArrayList$Itr.next(Unknown Source)
  at com.hasse.Muster.main(Muster.java:11)

这就会抛出一个下面的异常,迭代终止。

增强for循环

增强for循环的作用: 简化迭代器的书写格式。(注意:增强for循环的底层还是使用了迭代器遍历。)
增强for循环的适用范围: 如果是实现了Iterable接口的对象或者是数组对象都可以使用增强for循环。
增强for循环的缺点:增强for循环和iterator遍历的效果是一样的,也就说增强for循环的内部也就是调用iteratoer实现的,但是增强for循环有些缺点,例如不能在增强循环里动态的删除集合内容、不能获取下标等。

增强for循环的格式:

for(数据类型 变量名 :遍历的目标){
        //数据类型 变量名:声明一个变量用来接收遍历目标遍历后的元素
}

增强for循环要注意的事项:

  1. 增强for循环底层也是使用了迭代器获取的,只不过获取迭代器由jvm完成,不需要我们获取迭代器而已,所以在使用增强for循环变量元素的过程中不准使用集合对象对集合的元素个数进行修改。
  2. 迭代器遍历元素与增强for循环变量元素的区别:使用迭代器遍历集合的元素时可以删除集合的元素,而增强for循环变量集合的元素时,不能调用迭代器的remove方法删 除 元素。
  3. 普通for循环与增强for循环的区别:普通for循环可以没有遍历的目标,而增强for循环一定要有遍历的目标。
        int[] arr = {5,11,2,4,9,18}; 

        普通for循环的遍历方式 
        for(int i =  0 ; i<arr.length ; i++){ 
            System.out.println("元素:"+ arr[i]); 
        } 

        //使用增强for循环实现 
        for(int item :arr){ 
            System.out.println("元素:"+ item); 
        } 
      HashSet<String> set = new HashSet<String>();  
        //添加元素  
        set.add("张狗蛋");  
        set.add("张全蛋");  
        set.add("张傻蛋");  

        //使用迭代器遍历Set的集合. 
        Iterator<String> it  = set.iterator(); 
        while(it.hasNext()){ 
            String temp = it.next(); 
            System.out.println("元素:"+ temp); 
            it.remove(); 
        } 

        //使用增强for循环解决 
        for(String item : set){ 
            System.out.println("元素:"+ item); 

        } 

注意: Map集合没有实现Iterable接口,所以map集合不能直接使用增强for循环,如果需要使用增强for循环需要借助于Collection的集合。

HashMap<String, String> map = new HashMap<String, String>();  
        map.put("01","甲");  
        map.put("02","乙");  
        map.put("03","丙");  
        map.put("04","丁");  
        Set<Map.Entry<String, String>> entrys = map.entrySet();  
        for(Map.Entry<String, String> entry  :entrys){  
            System.out.println("键:"+ entry.getKey()+" 值:"+ entry.getValue());  
        }  

以上是关于迭代器和增强for循环的主要内容,如果未能解决你的问题,请参考以下文章

java基础第十二篇之集合增强for循环迭代器和泛型

为啥我可以在 Python for 循环中对迭代器和序列使用相同的名称?

Python迭代器和生成器

迭代器和生成器

迭代器和 for-of 循环

迭代器和for循环工作机制