在集合操作的时候,我们通常会使用foreach增强for循环遍历集合,比如我们想输出集合中的每个元素,我们可以使用for循环遍历。代码如下:
//初始化一个集合 static List< String > list = new ArrayList< String >(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); //遍历集合 for (String l : list) { System.out.println(l); }
但是当我们在使用增强for循环的时候,如果我们想在循环中删除一个或者多个元素的时候,直接调运集合的remove()方法是不行的,会报异常:java.util.ConcurrentModificationException。
for (String l : list) { if (l.equals("1")) { list.remove(l); } }
究其原因,是因为我们在使用集合的remove()操作的时候,java底层会去执行一个modCount++操作,修改modCount这个变量的值。同时我们在执行增强for循环的时候,本质上是在使用集合的Iterator,而这个Iterator也会维护这个modCount的变量,此外它还维护一个expectedModCount变量。也就是说集合本身会维护modCount变量,Iterator会维护modCount和exceptionModCount变量。但是每次在Iterator执行操作的时候,都会先检查modCount变量和exceptionModCount的值是否一致,源代码如下:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
在检查modCount和exceptionModCount的值是否还相同,如果不相同,那么就报异常。在上面for循环的操作中,我们使用for循环遍历,但是在循环内部使用集合自己的remove方法,这个方法把modCount的值给修改,接下来再遍历的时候,使用到了Iterator的方法,这时再检查那两个变量的时候,因为只有modCount被改了,所以他们不一致了,自然要抛异常。好了,现在明白为什么报异常以后,就知道怎么避免这个问题了。
我们有两个办法可以避免这个异常。
第一,不要使用集合Iterator相关的方法,不涉及到exceptionModCount变量即可,只涉及到modCount变量即可。说具体点就是我们不要使用任何和Iterator相关的东西,也就是说不要使用争强for循环,当然这样就不会执行检查两个变量是否相同了。代码体现如下:
for (int i = 0; i < list.size(); i++) { if (list.get(i).equals("4")) { // list.remove(i); list.remove(list.get(i));//只使用到集合自己的remove方法,不会涉及到exceptionModCount } }
第二,我们每次操作的时候,不要只修改modCount变量,同时修改exceptionModCount变量,使之永远保持一致即可。也就是说不要使用集合自己remove方法,使用iterator提供的方法。代码体现如下:
Iterator< String > itList = list.iterator(); while (itList.hasNext()) { if (itList.next().equals("1")) { itList.remove();//使用Iterator的remove方法,这样modCount和exceptionModCount永远是一致的 } }
第三,我们还有个一个择中的办法。首先使用iterator的方法得到所有需要被删除的元素,然后在使用集合的removeAll()方法一次性将要删的的元素都删除,在removeAll方法中,我们也不会涉及到检查modCount和exceptionModCount是否一致的问题。
这里只列举了List集合的例子,对于Set集合和Map集合是相同的。
相关推荐
在Java编程中,集合类遍历的同时进行删除操作是一个常见的需求,但如果不正确地执行,可能会导致`ConcurrentModificationException`。这个问题主要出现在迭代器正在遍历集合时,集合本身被修改的情况。以下是对这个...
然而,当我们尝试在使用`Iterator`遍历集合的过程中直接修改集合时,可能会遇到`ConcurrentModificationException`异常。这个异常通常发生在多线程环境下对共享数据进行并发修改,但即使在单线程情况下,如果在迭代...
通过上述分析可以看出,`<s:iterator>`标签是Struts2框架中非常实用的一个功能,它简化了集合遍历的过程,使得开发者可以更加专注于业务逻辑的实现。同时,我们也需要注意到在实际项目中可能遇到的一些问题,并采取...
- 避免越界:在遍历过程中确保索引不会超出数组长度,否则会导致`IndexOutOfRangeException`异常。 - 修改数组:在foreach循环中,如果尝试修改数组元素,可能会导致编译错误,因为foreach循环不支持在迭代过程中...
遍历是一种基本的编程技术,常用于访问树、图或其他集合中的每个元素。这种技术广泛应用于各种编程语言,如Java、C++、Python等。 遍历的目的通常是为了执行特定操作(如搜索、排序、更新或统计)或者理解数据结构...
为了解决这个问题,我们需要确保每次循环只调用一次 `next()` 方法,并将返回的键存储在一个局部变量中,然后使用这个变量进行操作。修正后的代码如下: ```java // 使用迭代器遍历 Iterator<String> it = ...
遍历是一种程序设计的基本操作,用于访问或处理集合中的每个元素,无论是数组、列表、字符串还是其他结构。对于十六进制遍历,这通常涉及到从最低有效位到最高有效位逐个处理每一位,或者按照特定步长(例如每四位一...
在Java编程中,`ConcurrentModificationException`是一个常见的运行时异常,通常发生在多线程环境下对集合进行迭代和修改操作时。此问题的核心在于,Java的集合类(如ArrayList、LinkedList、HashSet等)并不支持...
集合框架还提供了`Iterator`和`Stream`接口,用于遍历和操作集合。`Iterator`是传统迭代方式,`Stream`是Java 8引入的新特性,支持函数式编程风格,如过滤、映射和聚合操作。 总的来说,理解并熟练掌握Java的异常...
本文将深入探讨在JAVA基础测试中常见的异常问题,帮助开发者更好地理解和解决这些问题。 1. **运行时异常**:Java中的运行时异常(RuntimeException)是程序设计错误引起的,如空指针异常(NullPointerException)...
- 集合的遍历:通过for循环可以逐个遍历集合中的元素,但遍历顺序是不确定的,因为集合是无序的。 4. 固定集合(frozenset): - 定义:frozenset是集合的一个不可变版本,一旦创建就不能修改。它可以作为字典的...
Collection 集合体系提供了多种方式来存储和操作数据,但在多线程环境下,需要注意并发修改异常的出现原因和解决方法,以免程序出现错误。 Collection 集合体系的知识点总结: * Collection 集合体系的顶层接口是 ...
4. **避免在迭代过程中修改集合**:如果可能,尽量避免在遍历集合时对其进行修改,这包括在Linq查询中。 5. **使用`AsEnumerable()`或`AsQueryable()`**:这些方法可以创建一个只读的视图,但请注意,这并不能解决...
- 当尝试在遍历字典的过程中直接修改字典时(如删除元素),Python解释器为了保持数据结构的一致性,会抛出 `RuntimeError` 异常。 - 原因在于字典迭代器会在遍历过程中调用 `next` 方法,而直接删除字典元素会改变...
2. **异常处理**:在JSP中使用条件标签(如`<c:if>`)或在Java代码中进行异常处理,避免访问不存在的属性或空集合。 3. **EL表达式优化**:使用EL的`empty`操作符检查变量或集合是否为空,如`${not empty user....
在Java编程中,集合操作是不可或缺的一部分,它们用于存储、管理以及操作对象。这篇博文将深入探讨Java集合框架,包括其基本概念、常见类、接口和实现方式,以及如何进行有效的集合操作。以下是对这些知识点的详细...
递归遍历是指当目录中包含子目录时,程序将进入子目录内部,再次执行遍历操作。这个过程会一直持续到所有的子目录都被遍历完成。递归遍历是处理含有子目录的文件夹的自然和有效方式。 知识点5:使用List集合存储...
**解决:** 当在遍历集合的同时对其进行修改时,会引发这个异常。可以通过以下方式解决: - **使用线程安全集合:** 使用线程安全的集合,如`ConcurrentHashMap`。 - **安全修改集合:** 在遍历时如果需要修改集合,...
4. **Iterator接口**:学习如何遍历集合中的元素。 5. **泛型**:了解泛型的基本概念和使用,以提高代码的类型安全性和重用性。 6. **List接口与实现类**:熟练运用ArrayList和LinkedList,理解它们之间的性能差异。...
原因在于,在增强for循环中,实际上是使用Iterator来遍历List,而Iterator并不能检测到List的变化,从而导致异常。 解决方法 要解决List遍历删除元素的问题,可以使用Iterator来遍历List,并使用Iterator的remove...