迭代器模式

迭代器模式是在我们日常工作中常用到的一种。当我们使用Java遍历集合的时候,使用的就是迭代器模式。为了理解迭代器模式,我们就那Java中集合遍历的代码来解释分析一下。

// 定义Student类,省略了构造方法和getter/setter
public class Student {
    private String name;
    private String address;
    private String gender;
}

// 定义client
public class Client {
    public static void main(String[] args) {
        List<Student> studentList = studentGenerator();

        Iterator<Student> iterator = studentList.iterator();

        while (iterator.hasNext()) {
            Student student = iterator.next();
            System.out.println(student);
        }
    }

    private static List<Student> studentGenerator() {
        Student s1 = new Student("张三", "北京", "男");
        Student s2 = new Student("李四", "天津", "男");
        Student s3 = new Student("王五", "河北", "男");
        Student s4 = new Student("赵柳", "北京", "女");

        List<Student> studentList = new ArrayList<>(4);
        studentList.add(s1);
        studentList.add(s2);
        studentList.add(s3);
        studentList.add(s4);

        return studentList;
    }
}

// 输出内容
Student{name='张三', address='北京', gender='男'}
Student{name='李四', address='天津', gender='男'}
Student{name='王五', address='河北', gender='男'}
Student{name='赵柳', address='北京', gender='女'}

通过上面我们看到通过Iterator(迭代器)遍历学生集合,其中最关键的2个方法就是:

  • hasNext() 判断迭代的集合中是否还存在元素
  • next() 获取当前元素

为了一探究竟,我们先看看 Iterator 的源码:

public interface Iterator<E> {
    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }

Iterator 是一个接口,提供了4个方法,其中2个有默认实现,另外2个没有默认实现的就是 hasNext()Next() 。由于上文中我们使用的是 ArrayList ,接下来我们看看 ArrayList 是如何实现这2个方法的。通过阅读源码我们可以发现, ArrayList 内部定义了一个 Itr 实现了 Iterator 接口。源码如下(对 hasNext()next() 方法加了注释):

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;

        Itr() {}

        // 判断迭代的元素下标是否和集合元素个数相等,如果相等说明没有多余的元素了。
        public boolean hasNext() {
            return cursor != size;
        }

        // 最重要的就是最后一行代码,直接返回elementData[i],从数组选取第i个元素返回。其他的就是一些校验可以暂时忽略
        @SuppressWarnings("unchecked")
        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];
        }

        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();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        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();
        }
    }

通过上面,我们可以看出迭代器需要有以下几种元素:

  • 抽象集合:即里面的 List<T> 。(如果只有一个元素为什么还需要迭代遍历呢?是吧。)
  • 具体的集合:即里面的 ArrayList<Student> 。需要明确迭代哪个集合。
  • 抽象的迭代器:即 Iterator<T>
  • 具体的迭代器:即 ArrayList 里面的 Itr

在日常工作中,如果想需要去需要自己实现迭代器的话,其实就实现Java中的 Iterator 就可以了。当然你也可以自己搞一下自己的抽象迭代器接口,但是必需要有最关键 hasNext()next() 方法。

全部评论

相关推荐

你见过凌晨四点的牛客吗_BY_KobeBryant:明年再投都一样😂😂
点赞 评论 收藏
分享
谁知道呢_:要掉小珍珠了,库库学三年,这个结果
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务