Java8,iterator的forEachRemaining中remove可能抛异常

来源:互联网 发布:传世登录器源码 编辑:程序博客网 时间:2024/06/04 19:03

Java8的官方文档中,对于iterator的forEachRemaining的用法介绍如下:

default void forEachRemaining(Consumer<? super E> action)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.Implementation Requirements:The default implementation behaves as if:     while (hasNext())         action.accept(next());
详见:https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html

如果按照文档上的理解似乎可以在forEachRemaining的过程中remove元素:

ArrayList<String> list = new ArrayList();        for (int i = 0; i < 10; i++) {            list.add(String.valueOf(i));        }        Iterator iterator = list.iterator();        iterator.forEachRemaining(new Consumer() {            @Override            public void accept(Object o) {                System.out.println(o);                  if (o.equals("3") ) {                      System.out.println("remove");                      iterator.remove();                  }            }        });
但是,却会报异常java.lang.IllegalStateException,和文档描述不一样。其实是因为在ArrayList中,接口Iterator的forEachRemaining方法被覆盖时,和接口文档描述不一致导致的。

private class Itr implements Iterator<E> { //arraylist的实现    int cursor;       // index of next element to return    int lastRet = -1; // index of last element returned; -1 if no such    int expectedModCount = modCount;    public boolean hasNext() {        return cursor != size;    }    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; //只有所有acconsumer都执行完时,才会调整lastRest的值        checkForComodification();    } }

原因如下:

①在ArrayList内的Iterator中,remove基于lastRet。

②next()后,lastRest属性会赋值为刚刚获取的元素的index。

③在remove后,lastRet会被置为-1,而且remove(),会校验lastRet值是否>=0,所以导致了一次next(),只能remove一次。

④而调用forEachRemaining就会遇到问题了,它在循环执行consumer的过程中,并非调用next(),而是手动的去向后遍历,在这个过程中并未将lastRet置为刚刚获取对象的index。只有遍历到最后一个以后,才会修改lastRet值。

所以一旦在cousumer中调用remove(),就有可能遇到lastRe为-1的情况,触发java.lang.IllegalStateException。





阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 求女朋友原谅送什么花 求女朋友原谅的方法 求男朋友原谅的话 亲亲老婆求原谅 滕奕扬 求女友原谅的话 犯错了求女朋友原谅 求老婆原谅的暖心话 求女孩子原谅的话 怎样求女朋友原谅 求原谅的句子哄女孩的 求女朋友原谅的真心话 伤害了老婆求原谅的话 总裁为求女主原谅自罚 求女友原谅送什么花 求女友原谅的句子 怎么求老婆原谅 犯错了求老婆原谅的话 原谅话题 惹对象生气了求原谅的话 丰满反义泀 冷清反义泀 高考反义疑问句 求合作项目 求同存异 求同存异什么意思 求同存异的意思 求网址哪位大神懂的 求网址哪位大神懂得 求大神给一个更新快的网站 求大神这是什么歌 求大神ps 2018跪求大神给个网址 求大神把我p成亚索 求大神ps的后果全集 大神求嫁 怎么求姻缘 去哪里求姻缘 烧香求姻缘 红螺寺求姻缘注意事项 如何求姻缘 哪里求姻缘灵