Java的foreach有啥不同

Posted Danny_姜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java的foreach有啥不同相关的知识,希望对你有一定的参考价值。

陈述事实现象

foreach循环

从JDK 5开始,Java可以使用foreach对数组或者实现了Iterator的集合进行遍历。

对上述代码进行反编译,可以得出如下字节码:

可以看出,在编译时期Java编译器对foreach语法进行的字节码优化--使用Iterator对其进行转换。因此上述Java代码等同于如下代码:

注:foreach实际上是一种语法糖,所谓语法糖就是通过编译器或者其它手段对代码进行优化,让开发人员更加方便使用。

透过现象看本质

foreach循环

foreach确实在一定程度上,方便了对集合的遍历操作。但是在实际使用过程中,也是有坑存在的。比如以下代码:

图中红框中代码表示,在遍历集合的同时判断如果num等于1,则删除此元素。但是运行上述代码,会报如下错误:

Itr是ArrayList的内部类,当使用foreach对ArrayList进行遍历时,会通过它进行遍历。在其内部有个安全校验机制就是判断自带变量expectedModCount是否和ArrayList中的变量modCount相等,如果不相等,则直接抛出ConcurrentModificationException异常。

正常遍历的情况下,这两个值是一直相等的;但是如果在遍历时,对ArrayList的元素进行删除操作,则会导致expectedModCount != modCount。

一生二,二生三,三生万物

边遍历,边操作

那该如何实现边遍历边删除呢?刚才我们已经分析出产生ConcurrentModificationException异常的原因是Itr中的变量expectedModCount和ArrayList中的变量modCount不相等,导致Itr调用next方法校验失败。

而造成expectedModCount != modCount的原因是调用了ArrayList.remove方法进行删除操作。

所以如果想实现边遍历边删除,则不能直接调用ArrayList.remove方法。实际上在Itr中已经提供了相对应的remove方法,如下所示:

可以看出在实际上只是在调用ArrayList.remove方法之后,重新将modCount的值赋值给expectedModCount。这样下次调用next方法遍历时,依然可以通过校验。

因此需要手动使用Iterator对ArrayList进行遍历时,同时使用Itertor自身的remove方法删除元素即可,如下所示:


如果你喜欢本文

长按二维码关注

以上是关于Java的foreach有啥不同的主要内容,如果未能解决你的问题,请参考以下文章

在C#中for循环和foreach循环有啥区别?

向 div 添加事件监听器适用于 ForEach() 方法,但不适用于 for 循环。有啥不同?

现在有啥好用的java开发框架

有啥办法可以打破 foreach 循环?

Qt中的foreach有啥问题?

.map、.every 和 .forEach 之间有啥区别?