Java collection的Iterator的使用

看到了Java核心技术一书的集合的迭代器,写篇文章记录一下

interface Iterator<E>,有四个方法:hasNext(),next(),remove(),forEachRemaining(),最后一个方法是JDK1.8新增的

接下来使用迭代器中的方法遍历一个collection

1.传统方式,使用hasNext(),next()

 public static void main(String[] args) {
        Collection<String> collection = new ArrayList<>();
        collection.add("111");
        collection.add("222");
        collection.add("333");
        collection.add("444");
        //使用迭代器遍历集合
        Iterator<String> iterator = collection.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
}

next()源码:

private class Itr implements Iterator<E> {
        int cursor;// index of next element to return,要返回的下一个元素的索引,初始值0
        //返回最后一个元素的索引;如果没有返回,则返回-1
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        // prevent creating a synthetic constructor
        Itr() {}

        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;
            return (E) elementData[lastRet = i];
        }
}

第一次循环后:cursor变成了1,lastRet变成了0

第二次循环后:cursor变成了2,lastRet变成了1

第三次循环后:cursor变成了3,lastRet变成了2

第四次循环后:cursor变成了4,lastRet变成了3

应该将 Java 迭代器认为是位于两个元素之间 当调用 next 迭代器就越过下 一个元素,并返回刚刚越过的那个元素的引用,这一过程主要由cursor变量来控制。
 
如果想要删除集合里面的元素,需要先调用next(),再调用remove(),直接调用remove(),会报java.lang.IllegalStateException

        //使用迭代器遍历集合
        Iterator<String> iterator = collection.iterator();
        while (iterator.hasNext()){
            //System.out.println(iterator.next());
            iterator.remove();
            System.out.println(iterator.next());
        }

正确的写法是,将上面注释掉的代码恢复

remove()源码

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

每次都先判断lastRet的值是否小于0,在next()中lastRet的值才会被修改为>=0,所以要先调用next(),删除完成后lastRet又变成了-1,一次next()只能remove()一次

2.forEachRemaining(),对每个剩余元素执行给定的操作,直到所有元素都被处理或动作引发异常。注意是剩余两个字,很重要,看一个例子

public static void main(String[] args) {
        Collection<String> collection = new ArrayList<>();
        collection.add("111");
        collection.add("222");
        collection.add("333");
        collection.add("444");
        //使用迭代器遍历集合
        Iterator<String> iterator = collection.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("-------------------");
        //使用iterator的forEachRemaining
        iterator.forEachRemaining(item ->{
            System.out.println(item);
            //if ("333".equals(item))iterator.remove();
        });
}

输出如下:

111
222
333
444
-------------------

forEachRemaining没有遍历出任何元素,因为iterator里面的元素已经被第一种方法全部遍历出来了,iterator已经没有剩余元素了,看一下源码中参数的变化

将cursor变量的值赋给变量i,i<size才进行遍历, cursor为什么会等于4呢,是因为while循环的next()赋的值,此时在调用iterator的forEachRemaining方法就不会走if判断,所以剩余也是由cursor控制的。

forEachRemaining遍历过程中不能调用remove(),会报java.lang.IllegalStateException,例如下面的代码

        Collection<String> collection = new ArrayList<>();
        collection.add("111");
        collection.add("222");
        collection.add("333");
        collection.add("444");
        //使用迭代器遍历集合
        Iterator<String> iterator = collection.iterator();
//        while (iterator.hasNext()){
//            System.out.println(iterator.next());
//        }
        System.out.println("-------------------");
        //使用iterator的forEachRemaining
        iterator.forEachRemaining(item ->{
            System.out.println(item);
            if ("333".equals(item))iterator.remove();
        });

从上面的源码可以看到,forEachRemaining遍历的时候并没有使用next(),使用的是for循环遍历,并且需要等待全部遍历完成才会修改lastRet的值,当在遍历的过程中调用remove(),此时的lastRet仍旧为初始值-1,remove()有一个判断:

if (lastRet < 0)
   throw new IllegalStateException();

所以就抛出异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值