for循环和foreach的区别
关于for循环和foreach的区别,你真的知道,用了那么多年使用起来已经很熟悉了,可突然问我讲讲这两的区别,一下还真把我给卡住了一下,下面从源码的角度简单分析一下吧;
for循环的使用
for循环通过下标的方式,对集合中指定位置进行操作,每次遍历会执行判断条件 i<list.size(),满足则继续执行,执行完一次i++;
for(int i=0;i<list.size();i++)
{
System.out.println(i + ":" + list.get(i));
}
也就是说,即使在for循环中对list的元素remove和add也是可以的,因为添加或删除后list中元素个数变化,继续循环会再次判断i<list.size(); 也就是说list.size()值也发生了变化,所以是可行的,具体操作如下代码
for (int i = 0; i < list.size(); i++) {
if (i == 3) {
list.add("中间插入的一个字符串");
}
if (i == 5) {
{
list.remove(6);
}
}
System.out.println(i + ":" + list.get(i));
}
增强for循环:foreach循环的原理
同样地,使用foreach遍历上述集合,注意foreach是C#中的写法,在Java中写法依然是for (int i : list)
写法for(String str : list)
查看文档可知,foreach除了可以遍历数组,还可以用于遍历所有
实现了Iterable<T>
接口的对象。
用普通for循环的方式模拟实现一个foreach,由于List实现了Iterable<T>,
过程如下:首先通过iterator()方法获得一个集合的迭代器,然后每次通过游标的形式依次判断是否有下一个元素,如果有通过 next()方法则可以取出。 注意:执行完next()方法,游标向后移一位,只能后移,不能前进。
用传统for循环的方式模拟 增强for循环
和for循环的区别在于,它对索引的边界值只会计算一次。所以在foreach中对集合进行添加或删掉会导致错误,抛出异常java.util.ConcurrentModificationException
private static void testForeachMethod(ArrayList<String> list) {
int count = 0; // 记录index
for (String str : list) {
System.out.println(str);
count++;
if (count == 3) {
// foreach中修改集合长度会抛出异常
// list.add("foreach中插入的ABC");
}
}
}
具体可以从源码的角度进行理解
1.首先是调用iterator()方法获得一个集合迭代器
初始化时
expectedModCount记录修改后的个数,当迭代器能检测到expectedModCount是否有过修改
在创建迭代器之后,除非通过迭代器自身的 remove
或 add
方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException
。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException
。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。