Java中的for each实现原理与坑

文章转载自「开发者圆桌」一个关于开发者入门、进阶、踩坑的微信公众号java

Java中,遍历集合和数组通常有如下三种形式:程序员

 

for (int i = 0; i < list.size(); i++) {数组

    System.out.print(list.get(i) + ",");微信

}app

 

Iterator iter= list.iterator();工具

while (iter.hasNext()) {学习

    System.out.print(iter.next() + ",");ui

}spa

 

for (Integer i : list) {指针

    System.out.print(i + ",");

}

 

第一种是普通的for循环遍历,第二种是使用迭代器进行遍历,第三种咱们通常称之为加强for循环也就是for each循环。

 

for each实现原理剖析

 

咱们对如下代码进行反编译:

for(String str:list){

  System.out.print(str+",");

}

 

反编译后的代码是这样的:

String str;

for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.print((new StringBuilder(String.valueOf(str))).append(",").toString())){

   str = (String)iterator.next();

}

 

反编译后的代码虽然有点复杂,不过经过反编译,咱们看到Java中的for each循环底层是经过迭代器模式来实现的。

 

坑,当心哦

 

因为for each循环经过迭代器实现,那么必然有迭代器的特性。在Java中使用迭代器遍历元素的时候,在对集合进行删除的时候必定要注意,使用不当有可能发生ConcurrentModificationException,如如下代码:

for(String str:list){

System.out.print(str+",");

list.remove(str);

}

会抛出ConcurrentModificationException异常。

 

Iterator被建立以后会创建一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,当索引指针日后移动的时候就找不到要迭代的对象,因此会抛出ConcurrentModificationException异常。

 

Iterator 在工做的时候是不容许被迭代的对象被改变的。但你可使用 Iterator 自己的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

 

正确的在遍历的同时删除元素的姿式:

Iterator<String> Iter = list.iterator();    

while (Iter.hasNext()) { 

String str=Iter.next();

System.out.print(str+",");

        //注意不是list而是Iter的remove。

Iter.remove();    

}

 

这个细微的问题,可能在大部分状况下因为条件的限制不会出现,一旦条件知足,问题便暴露出来,这就是为何明明运行良好的代码忽然报错了。所以在使用for each循环时必定要注意这个坑。


延伸阅读

 

咱们在最初学习Java的时候,会接触到两个命令:javac和java,那个时候咱们就知道,javac是用来编译Java类的,就是将咱们写好的helloworld.java文件编译成helloworld.class文件。

 

那么反编译呢,就是经过helloworld.class文件获得java文件(或者说是程序员能看懂的Java文件)。

 

经常使用的反编译工具备jad、jd-gui等,本文使用的是jad,能够去https://varaneckas.com/jad/下载该工具。

相关文章
相关标签/搜索