`
sandy_leen
  • 浏览: 72157 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

遍历并批量删除容器中元素出现ConcurrentModificationException原因及处置

阅读更多

http://www.blogjava.net/sitinspring/archive/2007/12/03/165006.html

 

在以下四种遍历过程中,前两种会抛出ConcurrentModificationException,而后两种方法是正确的.

Department类:

 

package com.sitinspring;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Department {
	private String name;

	private List<Member> memberSheet;

	public Department(String name) {
		this.name = name;
	}

	public void addMemer(Member member) {
		if (memberSheet == null) {
			memberSheet = new ArrayList<Member>();
		}

		memberSheet.add(member);
	}

	public void printMemberSheet() {
		System.out.println("----部门" + name + "人员名单---");

		for (Member member : memberSheet) {
			System.out.println(member);
		}
	}

	/**
	 * 里面的四个清除过程请分别独立执行
	 *
	 */
	public void removeYoungerFromMemberSheet() {	
		// 遍历一:这个处理会抛出java.util.ConcurrentModificationException
		for (Member member : memberSheet) {
			if (member.getAge() < 30) {
				memberSheet.remove(member);
			}
		}
		
		// 遍历二:这个处理也会抛出java.util.ConcurrentModificationException
		for (Iterator it = memberSheet.iterator(); it.hasNext();) {
			Member member = (Member) it.next();

			if (member.getAge() < 30) {
				memberSheet.remove(member);
			}
		}
		
		// 遍历三:这个处理调用Iterator 本身的方法 remove(),会正常执行
		for (Iterator it = memberSheet.iterator(); it.hasNext();) {
			Member member = (Member) it.next();

			if (member.getAge() < 30) {
				it.remove();
			}
		}
		
		// 遍历四:这个处理不依赖Iterator,也会正常执行
		for (int i=0;i<memberSheet.size();i++) {
			Member member = memberSheet.get(i);

			if (member.getAge() < 30) {
				memberSheet.remove(member);
			}
		}
	}

	public String toString() {
		return name;
	}

	public String getName() {
		return name;
	}

	public static void main(String[] args) {
		Department resarchDept = new Department("研发部门");
		resarchDept.addMemer(new Member("张三", 38));
		resarchDept.addMemer(new Member("李四", 24));
		resarchDept.addMemer(new Member("王五", 30));
		resarchDept.addMemer(new Member("钱七", 22));
		resarchDept.addMemer(new Member("孙八", 39));
		resarchDept.addMemer(new Member("周九", 30));

		resarchDept.removeYoungerFromMemberSheet();
		resarchDept.printMemberSheet();
	}
}

 

Member类:

 

package com.sitinspring;

public class Member {
	private String name;

	private int age;

	public Member(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("员工名=" + name);
		sb.append(" 年龄=" + age);

		return sb.toString();
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}
}

 

 

为什么会发生这样的结果呢?这是因为

"当使用 fail-fast iterator 对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,即使是在单线程下运行, java.util.ConcurrentModificationException 异常也将被抛出。
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
"

上述这段资料来自http://hi.baidu.com/xjenator/blog/item/23b235a89041d4b0ca130c16.html.

java.util包中很多迭代器都是所谓的fail-fast迭代器.这些迭代器如果发现集合被修改,而且不是通过迭代器本身,那么抛出一个异常进行清除-ConcurrentModificationException-从而避免不安全行为的发生.

因此,第三种采用it.remove();不会出现任何异常,而第四不依赖于Iterator而依赖于索引当然更不会出现异常.

代码下载:
http://www.blogjava.net/Files/sitinspring/ConcurrentModificationTest20071203210937.rar

 

分享到:
评论

相关推荐

    HashMap和List遍历方法及如何遍历删除元素总结

    HashMap和List遍历方法及如何遍历删除元素总结 HashMap和List都是Java中最常用的数据结构,它们都可以用来存储和操作数据。然而,在遍历和删除元素时,需要小心地处理,以免出现问题。下面总结了HashMap和List的...

    Java HashMap 如何正确遍历并删除元素的方法小结

    这段代码将抛出 `java.util.ConcurrentModificationException` 异常,因为在遍历 HashMap 的元素过程中删除了当前所在元素,下一个待访问的元素的指针也由此丢失了。 2. 正确的删除方法 正确的删除方法是使用迭代...

    java中循环遍历删除List和Set集合中元素的方法(推荐)

    在Java编程中,遍历并删除集合(如List或Set)中的元素是一项常见的操作,但如果不正确地执行,可能会导致`ConcurrentModificationException`异常。这个异常通常在尝试修改正在迭代的集合时出现,因为Java的集合迭代...

    正确遍历删除List中的元素方法(推荐)

    在Java编程中,遍历并删除List中的元素是一项常见的操作,但如果不小心处理,可能会遇到错误,如`ConcurrentModificationException`。以下是几种常见的遍历删除List元素的方法及其注意事项: 1. **通过增强的for...

    使用Iterator接口遍历集合元素

    hasNext() 方法用于判断集合中是否还有未被遍历的元素,next() 方法用于返回集合中的下一个元素,remove() 方法用于删除集合中的上一个元素。 Iterator 接口主要用于遍历集合元素,而不是提供盛装对象的能力。因此...

    java.util.ConcurrentModificationException 异常问题详解1

    这个示例代码尝试在遍历 ArrayList 时删除其中的一个元素,这将导致 ConcurrentModificationException 异常。 那么,为什么会抛出这个异常呢?我们可以通过查看 ArrayList 的源码来了解原因。ArrayList 的 iterator...

    java哈希遍历_哈希遍历_

    - 在多线程环境下,不要在遍历过程中修改HashMap,否则可能会抛出`ConcurrentModificationException`。如果需要在遍历中修改,可以使用`Iterator.remove()`方法,或者使用`CopyOnWriteArrayMap`等线程安全的集合。 -...

    java批量删除列表内容

    5. **异常处理**:在执行批量删除时,应捕获并处理可能出现的异常,例如`NoSuchElementException`或`ConcurrentModificationException`。 6. **性能考量**:批量删除操作的时间复杂度与所选数据结构和删除策略有关...

    java-遍历map

    - 在遍历`Map`时,如果在遍历过程中尝试修改`Map`(例如添加或删除元素),可能会引发`ConcurrentModificationException`异常。因此,在遍历的同时不要修改`Map`。 - 使用流API遍历时,虽然代码更简洁,但性能上可能...

    Iterator遍历过程中list删除导致异常

    当你想在迭代过程中删除元素时,应该使用`Iterator`的`remove()`方法,而不是直接调用集合的`remove()`方法。这样,`Iterator`会正确处理集合的内部状态,避免异常: ```java List&lt;String&gt; list = new ArrayList...

    Java如何在List或Map遍历过程中删除元素

    在Java编程中,遍历并删除List或Map中的元素是一个常见的任务,但如果不理解其内部机制,可能会导致一些未预期的问题。本文将深入探讨在Java中如何安全地在List和Map遍历过程中删除元素。 首先,我们来看List的遍历...

    java集合类遍历的同时如何进行删除操作.docx

    在Java编程中,集合类遍历的同时进行删除操作是一个常见的需求,但如果不正确地执行,可能会导致`ConcurrentModificationException`。这个问题主要出现在迭代器正在遍历集合时,集合本身被修改的情况。以下是对这个...

    【Java面试题】List如何一边遍历,一边删除?

    在Java编程中,遍历并删除List集合是一个常见的操作,但在实际编程中,如果不使用正确的方法,可能会导致`java.util.ConcurrentModificationException`异常。本文主要针对这个面试题,详细讲解如何在遍历List的同时...

    Java中遍历ConcurrentHashMap的四种方式详解

    Java中遍历ConcurrentHashMap的四种方式详解 Java中遍历ConcurrentHashMap的四种方式详解是Java开发中一个非常重要的知识点。ConcurrentHashMap是Java中一种高效且线程安全的HashMap实现,它提供了高效的读写操作...

    在list集合中输入元素,去除重复的元素并输出

    这种方法通过迭代器(Iterator)来遍历列表,并在遍历过程中删除重复的元素。这种方式可以有效地避免`ConcurrentModificationException`异常。 ```java Iterator&lt;Integer&gt; iterator = list.iterator(); while ...

    java中List对象集合的遍历方法(三个)

    如果在遍历过程中需要移除元素,必须使用`it.remove()`,直接调用`list.remove()`会导致并发修改异常(ConcurrentModificationException)。 ### 第二种:增强型for循环(foreach) ```java for (A a : list) { /...

    各容器与迭代器的用法.docx

    容器是用来存储和管理对象的集合类,而迭代器则是用来遍历和访问容器中元素的接口。本篇将详细介绍几种常见的容器类(如LinkedList、Vector、ArrayList和Hashtable)以及它们的迭代器用法。 1. **LinkedList**: ...

    如何遍历一个java集合

    在面试中,除了基本的遍历方式,还可能考察一些高级话题,如并发遍历(ConcurrentModificationException)、性能优化(如避免在循环中调用`size()`方法)以及如何处理null元素等。同时,理解不同集合类的底层实现和...

    java 使用foreach遍历集合元素的实例

    在本实例中,我们将深入探讨如何使用`foreach`循环遍历集合元素,并理解其工作原理以及可能遇到的问题。 首先,让我们看下给出的代码示例: ```java import java.util.*; public class ForeachTest { public ...

Global site tag (gtag.js) - Google Analytics