foreach 循环的底层原理及正确使用方式,一定要掌握这些!
阅读本文大概需要 3.5 分钟。
来自:blog.csdn.net/m0_51358164/article/details/126665934
前言
ConcurrentModificationException
。一、foreach底层实现原理
for(Type item : arrayOrList) { }
代码时,会进行代码的转译。for(int i=0;i<array.length;i++) {
Type item = array[i];
System.out.println(item);
}
java.lang.Iterable
接口,在iterator()
方法中返回一个Iterator迭代器。Iterator iterator = strings.iterator();
while(iterator.hasNext()){
String string = (String)iterator.next();
System.out.println(string);
}
二、foreach使用限制
foreach在遍历集合的过程中不能修改集合中元素的值。不过,如果遍历的是数组,则不受此限制。 foreach在遍历过程中不能往集合中增加或删除元素,否则会抛出 ConcurrentModificationException
异常。即使在个别特殊情况下没有抛出这个异常,那也是因为巧合(下文会有说明)。遍历过程中,集合或数组中同时只有一个元素可见,即只有“当前遍历到的元素”可见,而前一个或后一个元素是不可见的。 只能从前往后正向遍历,不能反向遍历。
错误使用实例
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
final String toRemove = "2";
final String toAdd = "1000";
for (String item : list) {
//item = "100"; //这句执行无效,仅仅改变迭代器中item的指向,并不会真正改变list中的元素
if (toRemove.equals(item)) {
list.remove(item); //仅当toRemove为"3"时,没有报异常。这是删除倒数第二个元素情况下的“巧合”。
//list.add(toAdd); // 报ConcurrentModificationException
}
}
modCount
,用来记录list内部元素改变的次数。扩展:最全的java面试题库iter=list.iterator()
返回一个新的迭代器对象的时候,iter内部会用expectedModCount
成员变量记录下当时的modCount的值。在整个循环的遍历过程中,不管是iter.next()
还是iter.remove()
方法都会检查原ArrayList的modCount值是否与iter内部记录的expectedModCount
值一致,一旦不一致就会抛ConcurrentModificationException
。因此,异常是在增减集合元素后,下一轮循环的iter.next()
方法中抛出的。public boolean hasNext() {
return cursor != size;
}
public E next() {
// 此处抛出异常
checkForComodification();
// 省略其他代码...
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
iter.hasNext()
(hasNext只是返回迭代器内部的迭代位置cursor是否已达到被迭代容器的size,本身不会抛异常)判断是否还有元素时,发现没有了,直接返回false,进而不会调用到iter.next()
方法。当然也就不会有从这个方法中抛出的异常啦。正确使用
for(int i=0;i<list.size();i++) {
String item = list.get(i);
if ("3".equals(item)) {
list.remove(i);//为了效率,这里最好不要用list.remove(item)
}
}
Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
String item = iter.next();
if ("4".equals(item)) {
iter.remove();
}
}
总结
ConcurrentModificationException
异常。——阿里巴巴Java开发规范(嵩山版)互联网初中高级大厂面试题(9个G) 内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper......等技术栈!
⬇戳阅读原文领取! 朕已阅