欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java设计模式(迭代器模式 - 概念及jdk迭代器解析)

程序员文章站 2022-06-19 15:14:19
学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)本文先介绍了迭代器模式的概念,并介绍了jdk中的迭代器源码,最后聊了下为什么需要迭代器模式。迭代器模式1、概念2、jdk中的迭代器3、为什么要有迭代器模式1、概念定义:提供一种方法顺序访问一个容器使用场景:遍历一个容器对象。对于开发者来说,几乎不会自己去实现一个迭代器。因为jdk已经帮我们实现好了。我们主要是对....

学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。
如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)

本文先介绍了迭代器模式的概念,并介绍了jdk中的迭代器源码,最后聊了下为什么需要迭代器模式。


1、概念

定义:提供一种方法顺序访问一个容器

使用场景:遍历一个容器对象。

对于开发者来说,几乎不会自己去实现一个迭代器。因为jdk已经帮我们实现好了。我们主要是对迭代器模式做个了解,看看Java中是怎么去实现迭代器模式的。

2、jdk中的迭代器

我们遍历一个list的时候,经常会用到foreach,如下

public class Test {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        for (String aList : list) {
            System.out.println(aList);
        }
    }
} 

将Test类,javac一下,生成class文件,再拖到Intellij IDEA中,发现变成了Iterator的方式。
Java设计模式(迭代器模式 - 概念及jdk迭代器解析)

我们重点看下ArrayList的迭代器是怎么实现的

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public Iterator<E> iterator() { return new Itr(); } } 

iterator方法返回了一个Itr类

首先Itr类实现了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());
    }
} 

接下来看Itr

private class Itr implements Iterator<E> {
    // next方法返回的元素的下标
    int cursor;       // index of next element to return
    // 最近一次调用next返回元素的下标(默认-1)
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    // 判断是否还有元素,通过游标是否等于size判断
    public boolean hasNext() {
        return cursor != size;
    }
    
    // 获取一下个元素
    @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;
        // 我们知道,arrayList是通过数组实现的
        return (E) elementData[lastRet = i];
    }
    
    // 删除一个元素
    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            // 移除的是上一次next返回的元素
            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;
        // 从cursor开始
        int i = cursor;
        if (i >= size) {
            return;
        }
        final Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        }
        // 对cursor - (size-1)的元素做处理,处理的行为是入参定义的函数
        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();
    }
}

3、为什么要有迭代器模式

对于容器对象的访问,必然会涉及遍历算法。如果将遍历封装到容器中,对于容器来说,承担的功能有点多。如果让用户自己实现,那又必须暴露容器的内部实现。所以使用迭代器模式,在客户访问类与容器体之间插入一个第三者-迭代器。

而且Java Iterator统一了迭代方法,不管是list,还是map,或者set等,都可以用Iterator遍历。


https://blog.csdn.net/u010647035/article/details/79826457