黑马程序员技术交流社区

标题: 【济南中心】集合迭代—神秘的倒数第二个元素 [打印本页]

作者: 大山哥哥    时间: 2016-12-31 15:50
标题: 【济南中心】集合迭代—神秘的倒数第二个元素
本帖最后由 大山哥哥 于 2017-7-24 17:27 编辑

集合迭代—神秘的倒数第二个元素
引言
学过基础班的同学估计都知道什么叫并发修改异常,即ConcurrentModificationException,之所以产生这个异常,是因为在迭代器遍历集合的过程中,是不允许集合对元素进行增删的,但却可以用迭代器去增删元素,如果你在迭代器遍历集合的时候,强行让集合对元素进行增删就会产生并发修改异常,比如下面的代码就会产生并发修改异常:
                              


这是因为在迭代器遍历集合的时候,让集合对元素进行了增删。
如下代码就不会产生并发修改异常:

这是因为迭代器遍历集合的时候,让迭代器对元素进行了增删。这也是并发修改异常这个类被设计出来的原因,下面是我从API上截取出来的类的介绍

问题
并发修改异常,这虽然是一个众所周知的知识点,但是问题却来了,当我们如果我们遍历到集合的倒数第二个元素的时候,让集合删除任意一个元素,并不会出现并发修改异常,我们去观察这一下现象,代码如下:


为什么会出现这样的问题呢?我们又去API查看此类的时候我们发先API中有如下的解释

并发修改异常这个类,并不能硬性保证是否出现并发修改,但是会尽最大努力,因此他的不能硬性保证就表现在了“倒数第二个元素”。
探究
但是仅仅只得到了这样一个结论,我还是不甘心。所以我们一起去看看迭代器的源码,为什么在倒数第二个元素就不能保证发生并法修改呢?为了方便大家理解什么是迭代器,我给大家做了一个迭代器和集合的简易模型。

通过上面的代码我们可以看出,迭代器的实现类是集合的内部类,迭代器其实就是在获取的集合底层数组存储的元素,每next()一次,索引就增加一次,这样就能把集合里面的元素都遍历出来了。
但是JDK中提供的迭代器的源码,并没有如此简单,请大家仔细查看下面的源码,必须明白每一个用红色矩形圈起来的代码的意思。

查看源码之后并且理解之后,我们再来回想我们的并发修改异常产生的原因参照下面代码

当我们遍历到第二个元素,删除完毕“abc2”元素的时候,modCount就自增了一次,接着迭代器调用hasNext()方法判断cursorsize是否相同,结果发现不同,接着调用next()的时候发现expectedModCountmodCount不同,所以就报出了并发修改异常。
现在我们再来看看为什么遍历到倒数第二个元素的时候,删除就不会报出并发修改异常呢?参照如下代码:

当我们遍历到倒数第二个元素,cursor的值是3,删除完毕“abc4”元素的时候,modCount就自增了一次,而size也从4变成了3,接着迭代器调用hasNext()方法判断cursorsize是否相同,结果发现相同都是3,所以返回false,那么while循环就会终止,就不会再继调用next()了。所以就不需要比较expectedModCountmodCount是否相同了,所以就不会再报出并发修改异常了。。

作者: 小鲁哥哥    时间: 2016-12-31 17:01
支持支持,写的很用心~
作者: 大山哥哥    时间: 2016-12-31 17:32
小鲁哥哥 发表于 2016-12-31 17:01
支持支持,写的很用心~

谢谢小鲁兄
作者: 大山哥哥    时间: 2016-12-31 17:32
小鲁哥哥 发表于 2016-12-31 17:01
支持支持,写的很用心~

谢谢小鲁兄
作者: 大山哥哥    时间: 2016-12-31 17:32
小鲁哥哥 发表于 2016-12-31 17:01
支持支持,写的很用心~

谢谢小鲁兄
作者: 月微怜    时间: 2016-12-31 19:59
哇。。好喜欢这类型的贴。。赞下
作者: 橘子哥    时间: 2017-1-3 14:26
好贴,已顶!
作者: SutMaceZo    时间: 2017-1-3 18:18
赞一个..............
作者: Mr.KevinヾY1n    时间: 2017-1-4 08:55
赞一个赞一个
作者: zhoubinjian    时间: 2017-1-4 20:48
好贴,来赞一个
作者: 一片叶~    时间: 2017-1-5 08:37
好东西,收藏,赞
作者: flying81621    时间: 2017-1-8 21:16
写的好用心好详细,感谢楼主分享这么好的东西给我们
作者: 笑对明天    时间: 2017-1-12 19:31
迭代器的并发修改异常,写的很详细,
作者: 贾文和    时间: 2017-1-14 16:12
嘿嘿嘿 前天刚学了.!!! 要用ListItrator用迭代器去添加元素~
作者: a469517790    时间: 2017-1-15 12:52
赞一个赞一个
作者: newu    时间: 2017-1-15 18:12
好东西,收藏,赞
作者: 史蒂芬·周    时间: 2017-4-2 22:51
老师拿枪指着我们脑袋让我们来顶贴,不顶不让毕业{:8_470:}
作者: 大山哥哥    时间: 2017-7-24 17:26
希望对大家有所帮
作者: chentudong    时间: 2017-7-24 21:29
不错,迭代器修改并发异常提的确值得注意。还有迭代删除集合元素时,注意顺序
作者: 衣小帅    时间: 2019-4-27 16:38
这样的技术贴牛批




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2