java基础之:迭代器详解?

一、为什么要使用迭代器?

前景:
因为像list这种有序的集合里边,可以直接通过for循环的方式get(index)遍历得到每一个元素, 而set这种没有无序集合,则不能通过get(index)得到集合里边的元素,java就提供了迭代器,虽增强for循环也能对无序的集合进行遍历,但其内部亦是采用迭代器实现。
优势:
迭代器提供一种对容器对象中的各个元素进行访问的方法,而又不需暴露该对象的内部细节。迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,即我们无需关心该序列的底层结构是什么样子的。只要拿到这个对象,使用迭代器就可以遍历这个对象的内部.

List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");
    for (int i = 0; i < list.size(); i++) {
        list.get(i);//可以通过for循环对list进行遍历
    }


    Set<String> set = new HashSet<>();
    set.add("1");
    set.add("2");
    set.add("3");
    set.add("4");
    for (int i = 0; i < set.size(); i++) {
        // 不能使用for循环对set进行遍历
    }

二、如何使用迭代器?

控制台打印:

java 迭代器 泛型 java迭代器详解_for循环


需要遍历的集合调用iterator()方法,返回一个迭代器对象,hashNext()方法判断这个集合里边是否还有未遍历完的元素,直到集合没有元素可遍历循环结束则结束

迭代器遍历while循环写法:

Set<String> set = new HashSet<>();
    set.add("1");
    set.add("2");
    set.add("3");
    set.add("4");

    Iterator<String> iterator = set.iterator();
    
    while (iterator.hasNext()) {
        String next = iterator.next();
        System.out.println(next);
    }

迭代器遍历for循环写法:

Set<String> set = new HashSet<>();
    set.add("1");
    set.add("2");
    set.add("3");
    set.add("4");

    for (Iterator<String> iterator = set.iterator(); iterator.hasNext(); ) {
        String next = iterator.next();
        System.out.println(next);
    }

控制台打印:

java 迭代器 泛型 java迭代器详解_java_02

三、List、Set迭代器实现原理及源码分析?

以List为例,因为List是接口,不可能有迭代器相关具体实现,所以查看某具体实现类(以ArrayList为例)源码(多态),在AarrayList中发现iterator()方法返回了一个Itr对象,进而跟进Itr类。

public Iterator<E> iterator() {
        return new Itr();
    }

Itr是一个内部类,Itr相关变量和实现迭代器相关细节的三个核心方法:

private class Itr implements Iterator<E> {
		int cursor;       
		int lastRet = -1; 
		int expectedModCount = modCount;
        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() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    hasNext();//此处省略方法具体实现,代码单独贴在下面,以便于分析
    next();//此处省略方法具体实现,代码单独贴在下面,以便于分析
    remove();//此处省略方法具体实现,代码单独贴在下面,以便于分析
    }

一、hasNext()判断是否有元素没有被遍历,其实现细节是判断当前list的长度是否等于游标

public boolean hasNext() {
            return cursor != size;
        }

二、next()返回游标当前位置的元素,并且游标位置+1

public E next() {
            checkForComodification();
            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];
        }

三、删除游标左边的元素,在执行完next()方法之后,该操作只能执行一次

public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

原理图如下:

java 迭代器 泛型 java迭代器详解_迭代器_03

四、补充:

for循环、增强for循环和迭代器的区别

1、迭代器是用于方便集合遍历的,实现了Iterable接口的集合都可以使用迭代器来遍历。使用迭代器遍历元素时,除了获取元素之外,只能做remove操作。

for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
            iterator.remove();//只能做remove操作。
        }

2、增强for循环,内部使用的是迭代器,所以它的操作对象是数组和可以使用迭代器的集合。遍历时只能获取元素,无法修改、删除、增加。

for (String s : list) {
        //无法修改、删除、增加。
        }

3、如果需要对遍历的对象做增删修改的操作,使用普通的for循环来操作。

for (int i = 0; i < list.size(); i++) {
            list.add(list.get(i));//增加对应元素
            list.remove(list.get(i));//删除对应元素
            list.set(0, list.get(i));//修改对应的元素
        }