本文目录
一.题是什么题?
二.阿里Java开发规范。
2.1 正例代码。
2.2 反例代码。
三.层层揭秘,为什么发生异常了呢?
3.1 第一层:异常信息解读。
3.2 第二层:抛出异常的条件解读。
3.3 第三层:什么是modCount?它是干啥的?什么时候发生变化?
3.4 第四层:什么是expectedModCount?它是干啥的?什么时候发生变化?
3.5 第五层:组装线索,直达真相。
四.这题的坑在哪?
4.1 回头再看。
4.2 还有一个骚操作。
五.线程安全版的ArrayList。
六.总结一下。
七.回答另外一个面试题。
八.扩展阅读。
7.1 fail-fast机制和safe-fast机制。
7.2 Java语法糖。
7.3 阿里Java开发手册。
一.题是什么题?
我第一次遇到这个题的时候,是在一个微信群里,阿里著名的"Java劝退师"小马哥抛出了这样的一个问题:
然后大家纷纷给出了自己的见解(注:删除了部分聊天记录):
后面在另外的群里聊天的时候(注:删除了部分聊天记录),我也抛出了这样的问题:
总结一下图片中的各种回答:
1.什么也不会发生,remove之后,list中的数据会被清空。
2.remove的方法调用错误,入参应该是index(数组下标)。
3.并发操作的时候会出现异常。
4.会发生ConcurrentModifyException。
你的答案又是什么呢?
在这里,我先不说正确的答案是什么,也先不评价这些回答是对是错,我们一起去探索真相,寻找答案。
二.阿里Java开发规范
有人看到题的第一眼(没有认真读题),就想起了阿里java开发手册(先入为主),里面是这样说的:
正是因为大多数人都知道并且读过这个规范(毕竟是业界权威)。所以呼声最高的答案是【会发生ConcurrentModifyException】。因为他们知道阿里java开发手册里面是强制要求:
不要在foreach循环里面进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。
但是不能因为他是权威,我们就全盘接受吧?
2.1 正例代码
所以我们眼见为实,先把手册里面提到的【正例代码】跑一下,如下:
从上面我们可以得到一个结论.......
等等,到这一步你就想得到结论了?你不对【一行代码为什么就替换了七行代码】好奇吗?
看到真相的时候,有时候再往前一步就是本质了。
源码之下无秘密,我再送你一张图,JDK1.8中Collection.removeIf的源码:
好了,已经到源码级别了,从这里我们验证了,阿里java开发手册里面的正例是对的,而且我还想给他加上一句:
如果你的JDK版本是1.8以上,没有并发访问的情况下,可以使用
Collection.removeIf(Predicate<? super E> filter)方法。使代码更加优雅。
2.2 反例代码
接下来我们看看【反例代码】的运行结果:
从执行结果来看,和我们预期的结果是一致。看着没有问题呀?
但是你别忘了,下面还有一句话啊:
把删除元素的条件从【公众号】修改为【why技术】就发生了异常:
java.util.ConcurrentModificationException