本文目录

一.题是什么题?

二.阿里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 正例代码

所以我们眼见为实,先把手册里面提到的【正例代码】跑一下,如下:

细心的读者可能发现了:咦,这个代码的22行为啥颜色不一样呢?

我帮你看看。

替换之后的代码是这样的:

从上面我们可以得到一个结论.......

等等,到这一步你就想得到结论了?你不对【一行代码为什么就替换了七行代码】好奇吗?

看到真相的时候,有时候再往前一步就是本质了。

源码之下无秘密,我再送你一张图,JDK1.8中Collection.removeIf的源码:

好了,已经到源码级别了,从这里我们验证了,阿里java开发手册里面的正例是对的,而且我还想给他加上一句:

如果你的JDK版本是1.8以上,没有并发访问的情况下,可以使用Collection.removeIf(Predicate<? super E> filter)方法。使代码更加优雅。

2.2 反例代码

接下来我们看看【反例代码】的运行结果:

从执行结果来看,和我们预期的结果是一致。看着没有问题呀?

但是你别忘了,下面还有一句话啊:

我们执行试一试: