讨论一下:Java的for循环是怎样执行的?

FreeDove 2011-07-14 09:07:33
public class Test {
public static void main(String[] args) {
List<Long> list = new ArrayList<Long>();
list.add(new Long(1);
list.add(new Long(2));
list.add(new Long(3));
list.add(new Long(4));
list.add(new Long(5));

for(Long l : list) {
System.out.println("run.");
list.remove(l);
}
}
}

运行报错:
run.
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at com.lance.Test.main(Test.java:31)

可见只循环了一次,第二次在for中判断是报错,可是我第一轮循环时仅remove了一个元素而已。

把for循环更改写法:
for(int i=0;i<list.size();i++) {
Long l = list.get(i);
list.remove(l);
System.out.println("run." + i + ", l=" + l + ", list.size():" + list.size());
}

运行结果:
run.0, l=1, list.size():4
run.1, l=3, list.size():3
run.2, l=5, list.size():2
循环了3次,正确的,因为前面几次循环都remove掉元素,到最后一次size为2,可是i已经累加到3了。

如果for中写法变成
for(int i=0, ls=list.size();i<l;i++)

没有每次重新读取list size,会出现下标越界。这也好理解。

只是像最前面的写法
for(Long l : list)
这种仅运行一次,第二次就报错了呢,报错的行数就是for的这一行,这时虚拟机在验证什么?
...全文
257 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
heriane 2011-07-15
  • 打赏
  • 举报
回复
for(Long l : list) 得到的只是一个对象 跟list没关系
FreeDove 2011-07-15
  • 打赏
  • 举报
回复
谢谢楼上,不知道方案一和方案二、三有什么较大的区别。看很多开源的似乎很喜欢第一种写法,可是那种觉得似乎不直观。
HeiBoyYang 2011-07-15
  • 打赏
  • 举报
回复
package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
* from http://hi.csdn.net/HeiBoyYang
*/
public class Sample {
public static void main(String[] args) {
List listone=new ArrayList();
listone.add("tom");
listone.add("two");
Iterator it=listone.iterator();
//方案一
while(it.hasNext()){
System.out.println(it.next());
}
//方案二
for(int i=0;i<listone.size();i++){
System.out.println(listone.get(i));
}
//方案三
for(Object a:listone){
System.out.println(a);
}

}

}
FreeDove 2011-07-15
  • 打赏
  • 举报
回复
明白了,编译成class文件时候换回这写法了哈~~
ChDw 2011-07-15
  • 打赏
  • 举报
回复
for(Long l : list) 这个只是编译器优化处理而已,就是我上面写的代码,完全等同于
Long l;
for(Iterator iterator = list.iterator(); iterator.hasNext();) {
l = (Long)iterator.next();
}

你找个反编译工具就可以看到了
FreeDove 2011-07-15
  • 打赏
  • 举报
回复
高手太多,再不结贴分就不够分了。。。

:)
xiaoyang880803 2011-07-15
  • 打赏
  • 举报
回复
API里面写得非常清楚。for( : )形式的循环实际上是创建了一个迭代器,不能在循环内部调用List的remove方法。而只能调用迭代器的remove
FreeDove 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 chdw 的回复:]

for(Long l : list) {

等同于

Long l;
for(Iterator iterator = list.iterator(); iterator.hasNext();)
l = (Long)iterator.next();


这里出现异常是因为一旦直接调用list.add/remove修改了list,iterator就不能用了


删除你应……
[/Quote]
呵呵,谢谢,这个回答最全面了。。。
还不想在循环里做数据结构的更改,不好控制,问这个只是好奇for(Long l : list)是怎么跑的而已。留着以后肯定用得上
皮皮 2011-07-15
  • 打赏
  • 举报
回复

List<Long> list = new ArrayList<Long>();
list.add(new Long(1));
list.add(new Long(2));
list.add(new Long(3));
list.add(new Long(4));
list.add(new Long(5));
Iterator it = list.iterator();
while(it.hasNext()) {
System.out.println("run."+it.next());

it.remove();
}


你for 的时候 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象.
Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
你可以使用 Iterator 本身的方法 remove() 来删除对象
ChDw 2011-07-15
  • 打赏
  • 举报
回复
for(Long l : list) {

等同于

Long l;
for(Iterator iterator = list.iterator(); iterator.hasNext();)
l = (Long)iterator.next();


这里出现异常是因为一旦直接调用list.add/remove修改了list,iterator就不能用了


删除你应该调用iterator.remove()方法!
FreeDove 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 heriane 的回复:]

for(Long l : list) 得到的只是一个对象 跟list没关系
[/Quote]
每轮循环这个对象都是从list里出来的,每轮都检查list的size,怎么跟list没关系。
再说这个和楼主那里的报错没关系吧?
FreeDove 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 tianrui_wang 的回复:]

最好在list没有变化的情况下操作,如遍历的操作,list有更新时就无法判断是哪个list了
[/Quote]
“list有更新时就无法判断是哪个list了”这话什么意思,可否详细些。
java里对list的操作都是通过引址的方式吧,不管怎么更新,都不会生成新的list,都是那个list,怎么无法判断呢?
FreeDove 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 chenchenyangll 的回复:]

for(Long l : list)
这样的循环里不能更改list

也就是不能调用list.remove之类的方法
[/Quote]
[Quote=引用 2 楼 chenchenyangll 的回复:]

就比如C++里使用iterator,你修改原有的数据结构(删除个元素什么的),这个iterator就不能用了

一样的道理
[/Quote]
哦,意思相当于是虚拟机里做了处理了,类似list.add之类的对list进行更改的都不行咯。。。
  • 打赏
  • 举报
回复
最好在list没有变化的情况下操作,如遍历的操作,list有更新时就无法判断是哪个list了
chenchenyangll 2011-07-14
  • 打赏
  • 举报
回复
就比如C++里使用iterator,你修改原有的数据结构(删除个元素什么的),这个iterator就不能用了

一样的道理
chenchenyangll 2011-07-14
  • 打赏
  • 举报
回复
for(Long l : list)
这样的循环里不能更改list

也就是不能调用list.remove之类的方法

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧