容器中的迭代器模式

Java 容器中的迭代器模式

容器

J a v a Java Java 中提供了两大类容器 C o l l e c t i o n Collection Collection M a p Map Map,大致框架图如下:

容器

迭代器模式

容器为我们提供了多种多样的保存对象的方式,对于容器的遍历,可能也会有多种方式,比如对于链表的遍历,可能希望容器类既可以提供从前往后的遍历,又可以提供从后往前的遍历,迭代器模式就是将集合对象的遍历操作从集合里面抽离出来,放到迭代器类里面,让两者职责更加单一。

一个基本的迭代器接口如下所示:

public interface MyIterator<E> {
    boolean hasNext();
    void next();
    E currentItem();
}

当要使用迭代器时,可以通过组合的方式让迭代器类获得容器对象,也可以让迭代器类成为容器类的内部类。下面的实现采用内部类的方式,实现了一个 M y A r r a y L i s t MyArrayList MyArrayList,只是为了演示迭代器模式,因此内部采用$ Java$ 内置的 A r r a y L i s t ArrayList ArrayList

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

public class MyArrayList<E> {
    ArrayList<E> arrayList;
    public MyArrayList() {
        this.arrayList = new ArrayList<E>();
    }
	//    得到具体的迭代器。
    public MyIterator<E> iterator() {
        return new MyArrayListIterator();
    }

    public void add(E e) {
        this.arrayList.add(e);
    }

    public void remove(int index) {
        this.arrayList.remove(index);
    }
    
    private class MyArrayListIterator implements MyIterator<E> {
        int currentIndex = 0;
        @Override
        public boolean hasNext() {
            return currentIndex < MyArrayList.this.arrayList.size() ;
        }

        @Override
        public void next() {
            currentIndex++;
        }

        @Override
        public E currentItem() {
            return  MyArrayList.this.arrayList.get(currentIndex);
        }
    }
    // 具体的测试
    public static void main(String[] args) {
        MyArrayList<String> myArrayList = new MyArrayList<>();
        myArrayList.add("a");
        myArrayList.add("b");
        myArrayList.add("c");
        MyIterator<String> iterator = myArrayList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.currentItem());
            iterator.next();
        }
    }
}

那么如果我们在容器的迭代过程中,删除了容器中的元素会发生什么呢?再来进行具体的测试:

public static void main(String[] args) {
    MyArrayList<String> myArrayList = new MyArrayList<>();
    myArrayList.add("a");
    myArrayList.add("b");
    myArrayList.add("c");
    myArrayList.add("d");
    MyIterator<String> iterator = myArrayList.iterator();
    iterator.next();
    iterator.next();
    //        myArrayList.remove(3);
    myArrayList.remove(1);
    System.out.println(iterator.currentItem());
}

会发生不可预期的结果,就是当我们删除不同的元素时,最后的输出和我们调用 n e x t ( ) next() next() 的预期输出是不一样的,并且会给编程人员造成比较大的困扰。因此在 J a v a Java Java 普通容器的内部是不允许在迭代过程中,对容器元素进行增删的,当在遍历过程中,进行增删的话,会直接报异常。那么是如何实现的呢?

通过记录一个 $modCount $值,在容器内部会记录 m o d C o u n t modCount modCount 值,每当对容器进行增删的时候, m o d C o u n t modCount modCount都会改变,在创建迭代器的时候,会将此 m o d C o u n t modCount modCount 值赋值给迭代器内部的 e x p e c t e d M o d C o u n t expectedModCount expectedModCount,在每次 n e x t ( ) next() next() 时进行判断,如果不相等,就直接抛出异常, J a v a Java Java 内部 A r r a y L i s t ArrayList ArrayList 实现如下:

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];
}

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

那么如何实现快照形式的迭代呢?使用快照的方式, C o p y O n W r i t e A r r a y L i s t CopyOnWriteArrayList CopyOnWriteArrayList 内部就是使用此方式。

// CopyOnWrite 内部使用的 snapshot
/** Snapshot of the array */
private final Object[] snapshot;
/** Index of element to be returned by subsequent call to next.  */
private int cursor;

private COWIterator(Object[] elements, int initialCursor) {
    cursor = initialCursor;
    snapshot = elements;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值