我是靠谱客的博主 含糊未来,最近开发中收集的这篇文章主要介绍遇到的关于Java迭代器的奇怪问题——迭代中remove不抛异常,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

某个和迭代器相关的问题。在最近的面试和笔试中遇到多次。

ArrayList<String> integers = new ArrayList<>();
        integers.add("1");
        integers.add("2");
        for(String s:integers){
            if(s.equals("1")){
                integers.remove("1");
            }
            if(s.equals("2")){
                integers.remove("2");
            }
        }

请问这个程序的结果是什么。我的第一反应,迭代的过程中,直接用集合的remove修改结构,这不是会因为midCount和迭代器的expectedMidCount不一致而导致抛出并发修改异常吗?然而我还是太单纯了,直到并发修改异常顶多说明你关注过源码,但是只有分析过迭代器源码的时候,才能够回到出以上的问题——没有任何输出(无异常)

foreach循环本质上就是hashNext()+next(),而核心的点就出在hasNext的实现上了

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

通过一个不等待去判断是否还具有下一个元素,其中size就是容器的大小,我们可以更改。而cursor下一个元素(严谨讲,hasNext()在next()之前调用,因此这里的cursor就是指代下一个元素的位置——类比我们去实现一个栈结构,这个就是指针指向下一个元素的位置)而当调用next()的时候,会检查两个modCount是否一致,并且将输出当前要迭代的元素arr[cursor],之后便将cursor自增。

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

现在我们有1 2 3 4 5 五个元素,假如当前调用next后,返回的是4,此时的size是5,cursor是4(元素4的索引是3,cursor自增后是4)。如果我们调用remove方法,删除某一个元素改变size。使得size == cursor 成立,那么迭代器将在倒数第二个元素就直接退出了,不会迭代最后一个元素

不一定是倒数第二个元素,只要能在迭代到某一个位置,如果当前索引是x,那么此时的cursor是x+1.然后删除若干元素,使得size等于cursor。那么再进行下一次hasNext()的时候就会提前退出。后面的元素都不会被迭代。

再次解释最开始的代码。当倒数第二个元素被删除之后,hasNext()返回false,导致循环退出。所以只有第一个remove被执行了,而第二个remove没有被执行。

再补充一个,基本都是之前面试遇到的奇葩问题。
如果边遍历数组,边删除一个元素。(删完元素之后,遍历不能停)

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 8, 9));
    for(int i=list.size()-1;i>=0;i--){
        Integer cur = list.get(i);
        if(cur==3)list.remove(cur);
    }
    System.out.println(list);
}

如果是正序删除元素,会导致后面的元素往前面补充,而导致有一个元素被跳过去,我们需要手动 index – 。或者直接使用倒序遍历的方式,当我们删除一个元素的时候,后面的内容会往前面复制,但是后面的内容我们都已经遍历过了,因此可以接着向后面进行遍历。

最后

以上就是含糊未来为你收集整理的遇到的关于Java迭代器的奇怪问题——迭代中remove不抛异常的全部内容,希望文章能够帮你解决遇到的关于Java迭代器的奇怪问题——迭代中remove不抛异常所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部