文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java中ArrayList陷阱实例分析

2023-06-29 07:26

关注

这篇文章主要介绍“Java中ArrayList陷阱实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java中ArrayList陷阱实例分析”文章能帮助大家解决问题。

问题分析

疑惑满满

小枫听到这个面试题的时候,心想这是什么水面试官,怎么问这么简单的题目,心想一个for循环加上equal判断再删除不就完事了吗?但是转念一想,不对,这里面肯定有陷阱,不然不会问这么看似简单的问题。小枫突然想起来之前写代码的时候好像遇到过这个问题,也是在ArrayList中删除指定元素,但是直接for循环remove元素的时候还抛出了异常,面试官的陷阱估计在这里。小枫暗自窃喜,找到了面试官埋下的陷阱。 小枫回想起当天的的测试情况,代码进行了脱敏改造。当初是要在ArrayList中删除指定元素,小枫三下五除二,酣畅淋漓的写下了如下的代码,信心满满的点了Run代码的按钮,结果尴尬了,抛异常了。

public class TestListMain {    public static void main(String[] args) {        List<String> result = new ArrayList<>();        result.add("a");        result.add("b");        result.add("c");        result.add("d");        for (String s : result) {            if ("b".equals(s)) {                result.remove("b");            }        }    }}

一个大大红色的异常马上就出来了,OMG,怎么会这样呢,感觉代码没什么问题啊,赶紧看看抛了什么异常,在哪里抛的异常吧。可以看出来抛了一个ConcurrentModificationException的异常,而且是在Itr这个类中的一个检测方法中抛出来的异常,这是怎么回事呢?我们的原始代码中并没有这个Itr代码,真是百思不得其解。

Java中ArrayList陷阱实例分析

拨云见日

既然从源代码分析不出来,我们就看下源代码编译后的class文件中的内容是怎样的吧,毕竟class文件才是JVM真正执行的代码,不看不知道,一看吓一跳,JDK原来是这么玩的。原来如此,我们原始代码中的for-each语句,编译后的实际是以迭代器来代替执行的。

public class TestListMain {    public TestListMain() {    }    public static void main(String[] args) {        List<String> result = new ArrayList();        result.add("a");        result.add("b");        result.add("c");        result.add("d");        //创建迭代器        Iterator var2 = result.iterator();        while(var2.hasNext()) {            String s = (String)var2.next();            if ("b".equals(s)) {                result.remove("b");            }        }    }}

通过ArrayList创建的Itr这个内部类迭代器,于是for-each循环就转化成了迭代器加while循环的方式,原来看上去的for-each循环被挂羊头卖狗肉了。

  public Iterator<E> iterator() {        return new Itr();    }

Itr这个内部类迭代器,通过判断hasNext()来判断迭代器是否有内容,而next()方法则获取迭代器中的内容。

 private class Itr implements Iterator<E> {        int cursor;       // index of next element to return        int lastRet = -1; // index of last element returned; -1 if no such        int expectedModCount = modCount;        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];        }     ...      }

大致的过程如下所示:

Java中ArrayList陷阱实例分析

真正抛异常的地方是这个检测方法, 当modCount与expectedModCount不相等的时候直接抛出异常了。那我们要看下modCount以及expectedModCount分别是什么。这里的modCount代表ArrayList的修改次数,而expectedModCount代表的是迭代器的修改次数,在创建Itr迭代器的时候,将modCount赋值给了expectedModCount,因此在本例中一开始modCount和expectedModCount都是4(添加了四次String元素)。但是在获取到b元素之后,ArrayList进行了remove操作,因此modCount就累加为5了。因此在进行检查的时候就出现了不一致,最终导致了异常的产生。到此我们找到了抛异常的原因,循环使用迭代器进行循环,但是操作元素却是使用的ArrayList操作,因此迭代器在循环的时候发现元素被修改了所以抛出异常。

Java中ArrayList陷阱实例分析

我们再来思考下,为什么要有这个检测呢?这个异常到底起到什么作用呢?我们先来开下ConcurrentModificationException的注释是怎么描述的。简单理解就是不允许一个线程在修改集合,另一个线程在集合基础之上进行迭代。一旦检测到了这种情况就会通过fast-fail机制,抛出异常,防止后面的不可知状况。

public class ConcurrentModificationException extends RuntimeException {    ...}

如何正确的删除

既然抛异常的原因是循环使用了迭代器,而删除使用ArrayList导致检测不通过。那么我们就循环使用迭代器,删除也是用迭代器,这样就可以保证一致了。

public class TestListMain {    public static void main(String[] args) {        List<String> result = new ArrayList<>();        result.add("a");        result.add("b");        result.add("c");        result.add("d");       Iterator<String> iterator = list.iterator(); while (iterator .hasNext()) {String str = iterator.next();if ("b".equals(str)) {iterator.remove();}    }}

关于“Java中ArrayList陷阱实例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯