文章转载自「开发者圆桌」一个关于开发者入门、进阶、踩坑的微信公众号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/下载该工具。