迭代器模式与Java Iterator源码

本文详细探讨了迭代器模式在Java中的实现,包括Iterator接口、Iterable接口、Itr和ListItr内部类的职责。同时,文章解释了在foreach遍历中删除元素导致的ConcurrentModificationException异常及其解决办法,分析了Java源码中如何通过修改迭代器状态来避免此异常。
摘要由CSDN通过智能技术生成

迭代器模式

迭代器模式是一种将集合的增删改操作与集合的顺序遍历操作分离的设计模式。集合只负责增删改操作,迭代器对于集合的内部类,专门负责顺序遍历。Java的Iterator是迭代器模式的经典实现。笔者jdk版本是11.0.4,不同版本的jdk的Iterator相关类及其实现有所不同,下面以jdk11.0.4为例。

Iterator

jdk定义了一个Iterator接口,声明了hasNext, next, remove方法,分别用于检查是否结束遍历、遍历下一个元素、删除元素的操作。

/**
 * An iterator over a collection.  {@code Iterator} takes the place of
 * {@link Enumeration} in the Java Collections Framework.  Iterators
 * differ from enumerations in two ways:
 *
 * <ul>
 *      <li> Iterators allow the caller to remove elements from the
 *           underlying collection during the iteration with well-defined
 *           semantics.
 *      <li> Method names have been improved.
 * </ul>
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
 * Java Collections Framework</a>.
 *
 * @apiNote
 * An {@link Enumeration} can be converted into an {@code Iterator} by
 * using the {@link Enumeration#asIterator} method.
 *
 * @param <E> the type of elements returned by this iterator
 *
 * @author  Josh Bloch
 * @see Collection
 * @see ListIterator
 * @see Iterable
 * @since 1.2
 */
public interface Iterator<E> {
   
    /**
     * Returns {@code true} if the iteration has more elements.
     * (In other words, returns {@code true} if {@link #next} would
     * return an element rather than throwing an exception.)
     *
     * @return {@code true} if the iteration has more elements
     */
    boolean hasNext();

    /**
     * Returns the next element in the iteration.
     *
     * @return the next element in the iteration
     * @throws NoSuchElementException if the iteration has no more elements
     */
    E next();

    /**
     * Removes from the underlying collection the last element returned
     * by this iterator (optional operation).  This method can be called
     * only once per call to {@link #next}.
     * <p>
     * The behavior of an iterator is unspecified if the underlying collection
     * is modified while the iteration is in progress in any way other than by
     * calling this method, unless an overriding class has specified a
     * concurrent modification policy.
     * <p>
     * The behavior of an iterator is unspecified if this method is called
     * after a call to the {@link #forEachRemaining forEachRemaining} method.
     *
     * @implSpec
     * The default implementation throws an instance of
     * {@link UnsupportedOperationException} and performs no other action.
     *
     * @throws UnsupportedOperationException if the {@code remove}
     *         operation is not supported by this iterator
     *
     * @throws IllegalStateException if the {@code next} method has not
     *         yet been called, or the {@code remove} method has already
     *         been called after the last call to the {@code next}
     *         method
     */
    default void remove() {
   
        throw new UnsupportedOperationException("remove");
    }

    /**
     * Performs the given action for each remaining element until all elements
     * have been processed or the action throws an exception.  Actions are
     * performed in the order of iteration, if that order is specified.
     * Exceptions thrown by the action are relayed to the caller.
     * <p>
     * The behavior of an iterator is unspecified if the action modifies the
     * collection in any way (even by calling the {@link #remove remove} method
     * or other mutator methods of {@code Iterator} subtypes),
     * unless an overriding class has specified a concurrent modification policy.
     * <p>
     * Subsequent behavior of an iterator is unspecified if the action throws an
     * exception.
     *
     * @implSpec
     * <p>The default implementation behaves as if:
     * <pre>{@code
     *     while (hasNext())
     *         action.accept(next());
     * }</pre>
     *
     * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */
    default void forEachRemaining(Consumer<? super E> action) {
   
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

Iterable

Iterable接口是可迭代对象的接口,其中iterator方法返回一个迭代器对象。

public interface Iterable<T> {
   
    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();

集合类的基类接口Collection中,实现了Iterable接口。

public interface Collection<E> extends Iterable<E>

Itr

在jdk11.0.4中,List集合的抽象基类AbstractList和具体的ArrayList类中都各自实现了迭代器内部类Itr, ListItr.
AbstractList.Itr为例,属性cursor是下一个元素的索引,lastRet是最后一次返回的元素的索引,一般来说是cursor - 1expectedModCount用于检查ConcurrentModification异常(下面会详述)。可以看到,相比于大家很容易想到的实现,jdk对于nextremove的实现中只是多了对于ConcurrentModification异常的检查checkForComodification(下面会详述).

private class Itr implements Iterator<E> {
   
    /**
        * Index of element to be returned by subsequent call to next.
        */
    int cursor = 0;

    /**
        * Index of element returned by most recent call to next or
        * previous.  Reset to -1 if this element is deleted by a call
        * to remove.
        */
    int lastRet = -1;

    /**
        * The modCount value that the iterator believes that the backing
        * List should have.  If this expectation is violated, the iterator
        * has detected concurrent modification.
        */
    int expectedModCount = modCount;

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

    public E next() {
   
        checkForComodification();
        try {
   
            int i = cursor;
            E next = get(i);
            lastRet = i;
            cursor = i + 1;
            return next;
        } catch (IndexOutOfBoundsException e<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值