今天看来一下Java中list集合部分的八股,发现了一个以前没注意过的问题,记录一下

list可以一边遍历一边修改元素吗?

答:在 Java 中,List在遍历过程中是否可以修改元素取决于遍历方式和具体的List实现类。

①:对于普通for循环,只要索引不超过list范围,可以一边遍历一遍修改

②:对于foreach循环,如果想边遍历边修改则必须使用迭代器的remove或set方法实现,否则会抛出异常。解释如下:

首先,需要知道的是,foreach循环是基于迭代器实现的,而在迭代器中有这样一个机制,即“快速失败” (Fail-Fast)机制

  1. 快速失败 (Fail-Fast) 机制

这里就提到了一个新的东西叫modCount,这里简单介绍一下:

  1. modCount (Modification Count):

    代码示例

    import java.util.ArrayList;
    import java.util.List;
    
    public class FailFastExample {
        public static void main(String[] args) {
            // 1. 创建一个ArrayList并添加元素
            List<String> names = new ArrayList<>();
            names.add("Alice");
            names.add("Bob");
            names.add("Charlie");
    
            // 2. 使用foreach循环遍历 (底层使用迭代器)
            for (String name : names) { 
            // Iterator<String> it = names.iterator();while(it.hasNext()) ...
    
                System.out.println(name);
    
                // 3. 在迭代过程中,尝试通过集合本身的remove方法删除元素 (错误的做法!)
                if (name.equals("Bob")) {
                    names.remove("Bob"); // 结构性修改! modCount++!
                }
            }
        }
    }

    对于这段代码的解释:

    关键总结

    1. modCount 是集合的“修改计数器”。 结构性修改会递增它。
    2. 迭代器创建时“拍照”记录 expectedModCount 它期望在迭代过程中,集合的 modCount 不应该改变(除非是迭代器自己的 remove() 方法,该方法会同步更新 expectedModCount)。
    3. next()(和 hasNext())检查一致性。 每次调用 next() 时,都会检查 modCount == expectedModCount
    4. 外部修改导致计数不一致。 如果在迭代过程中,通过集合自身的方法(如 list.add/removemap.put/remove)而非迭代器的 remove() 方法对集合进行了结构性修改,modCount 就会改变,而迭代器的 expectedModCount 不变。
    5. 检测到不一致立即抛出 ConcurrentModificationException 这就是“快速失败”的表现。
    6. foreach 循环依赖迭代器。 因此 foreach 循环天生就带有这种快速失败的特性。
    7. 避免异常: 如果需要在迭代中删除元素,必须使用迭代器自身的 remove() 方法。这个方法在删除元素后,会同步更新 expectedModCount 为新的 modCount,从而保持一致性。

    Logo

    有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

    更多推荐