List集合循环遍历删除修改保存内容的测试:以及报错:ConcurrentModificationException

本文深入探讨了Java中List集合的三种遍历方式:增强for循环、普通for循环和Iterator循环,详细分析了在不同情况下对List进行修改和删除操作的行为表现及潜在异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.taotao.cart.controller;

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

import com.taotao.manager.pojo.TbItem;
/**
 * List 集合中保存数据的修改和移除
 * -----------------测试一-------------------
 *   * 测试使用增强for循环删除和修改List保存对象
	 * 	1 移除list内的对象:
	 * 		1.1 循环删除多个对象时:报错java.util.ConcurrentModificationException
	 * 		1.2 只删除一个对象,然后使用break停止循环,则不报错
	 * 	2 修改内容不报错
 * -----------------测试二-------------------
 * 	 * 测试使用普通for循环删除和修改List保存对象
	 * 	1 移除list内的对象:
	 * 		1.1 升序循环
	 * 			1.1.1 循环删除多个对象时:不报错,但是数据有较大误差
	 * 			1.1.2 只删除一个对象,然后使用break停止循环:则不报错,且数据正确
	 * 		1.2 降序循环
	 * 			删除多个或一个都不报错,且数据准确
	 * 	2 修改内容不报错
 * 
 * -----------------测试三-------------------
 * 	 * 测试使用Iterator循环删除和修改List保存对象
	 * 	1 使用list移除其内的对象:
	 * 		1.1 移除多个 :报错java.util.ConcurrentModificationException
	 * 		1.2 移除一个 :不报错,数据正常
	 * 	2 使用Iterator移除list中的对象: 
	 * 		2.1 移除多个 :正确不报错
	 * 		2.2 移除一个:正确不报错
	 * 	3 修改内容不报错: 正确不报错
 * @Description 
 * @ClassName Tes
 * @Author [浅醉]
 * @Date 2019年2月27日 下午2:12:07
 */
public class Tes {
	public static void main(String[] args) {
		//test1();
		//test2();
		test3();
	}
	/**
	 * 测试使用增强for循环删除和修改List保存对象
	 * 	1 移除list内的对象:
	 * 		1.1 循环删除多个对象时:报错java.util.ConcurrentModificationException
	 * 		1.2 只删除一个对象,然后使用break停止循环,则不报错
	 * 	2 修改内容不报错
	 * 
	 */
	public static void test1(){
		List<Person> list = new ArrayList();
		Person p1 = new Person("张三", 1);
		Person p2 = new Person("李四", 2);
		Person p3 = new Person("王二", 3);
		
		list.add(p1);
		list.add(p2);
		list.add(p3);
		System.out.println(list.size());
		for(Person temp : list){
			
			
			/*-----------1.1 循环删除多个数据报错------------*/
			//list.remove(temp); 循环删除多个数据报错
			
			/*-----------1.2  删除一个数据,然后停止循环,则不报错------------*/
			if(temp.getName().equals("李四")){
				list.remove(temp);
				break;   
			}
			/*-----------1.3  修改数不报错------------*/
			//temp.setName("liili"); 
		}
		for(Person temp : list){
			System.out.println(temp.getName());
			
		}
		System.out.println(list.size());
	}
	/**
	 * 测试使用普通for循环删除和修改List保存对象
	 * 	1 移除list内的对象:
	 * 		1.1 升序循环
	 * 			1.1.1 循环删除多个对象时:不报错,但是数据有较大误差
	 * 			1.1.2 只删除一个对象,然后使用break停止循环:则不报错,且数据正确
	 * 		1.2 降序循环
	 * 			删除多个或一个都不报错,且数据准确
	 * 	2 修改内容不报错
	 * 
	 */
	public static void test2(){
		List<Person> list = new ArrayList();
		Person p1 = new Person("张三", 1);
		Person p2 = new Person("李四", 2);
		Person p3 = new Person("王二", 3);
		
		list.add(p1);
		list.add(p2);
		list.add(p3);
		System.err.println("操作前list集合大小:"+list.size());
		
		/*----------1.1.1 循环删除多个对象时:不报错,但是数据有较大误差------------*/
		
		/*for(int i = 0;i<list.size();i++){
			System.out.println("list的实时大小:"+list.size());
			System.out.println("被删除的数据:"+list.get(i).getName());
			list.remove(i);
		}*/
		/* 结果: 并没有全部删除,仍剩下一个数据 李四。
		 * 		是因为在循环删除时list集合大小变化了,而且数据的下标也变化了:
		 * 		张三的下标是0,当删除后李四的下标变成了0;王二的变成了1 ,故删除了王二,留下了李四。这是有错误的。
		 	3
			被删除的数据:张三
			被删除的数据:王二
			1
		 */
		
		/*----------1.1.2 只删除一个对象,然后使用break停止循环,则不报错,且数据正确------------*/
		
		/*for(int i = 0;i<list.size();i++){
			if(list.get(i).getName().equals("李四")){
				System.out.println("被删除的数据:"+list.get(i).getName());
				list.remove(i);
				break;
			}
		}*/
		
		/*----------1.2.1 降序循环 :循环删除多个数据,不报错,数据准确------------*/
		/*for(int i = list.size()-1;i>-1;i--){
			System.out.println("list的实时大小:"+list.size());
			System.out.println("被删除的数据:"+list.get(i).getName());
			list.remove(i);
		}
		*/
		
		/*----------1.2.2 降序循环 :删除一个数据,break。不报错,数据准确------------*/
		for(int i = list.size()-1;i>-1;i--){
			if(list.get(i).getName().equals("李四")){
				System.out.println("被删除的数据:"+list.get(i).getName());
				list.remove(i);
				break;
			}
		}
		
		
		
		System.err.println("操作后list集合大小:"+list.size());
	}
	/**
	 * 测试使用Iterator循环删除和修改List保存对象
	 * 	1 使用list移除其内的对象:
	 * 		1.1 移除多个 :报错java.util.ConcurrentModificationException
	 * 		1.2 移除一个 :不报错,数据正常
	 * 	2 使用Iterator移除list中的对象: 
	 * 		2.1 移除多个 :正确不报错
	 * 		2.2 移除一个:正确不报错
	 * 	3 修改内容不报错: 正确不报错
	 * 
	 */
	public static void test3(){
		List<Person> list = new ArrayList();
		Person p1 = new Person("张三", 1);
		Person p2 = new Person("李四", 2);
		Person p3 = new Person("王二", 3);
		
		list.add(p1);
		list.add(p2);
		list.add(p3);
		System.err.println("操作前list集合大小:"+list.size());
		
		/*----------1.1 使用list移除其内多个对象: java.util.ConcurrentModificationException------------*/
		/*Iterator<Person> iterator = list.iterator();
		int i = 0;
		while(iterator.hasNext()){
			Person person = iterator.next();
			list.remove(person);
		}*/
		
		
		/*----------1.2 使用list移除其内一个对象:不报错,数据正常------------*/
		Iterator<Person> iterator = list.iterator();
		while(iterator.hasNext()){
			Person person = iterator.next();
			if(person.getName().equals("李四")){
				list.remove(person);
				break;
			}
		}
		
		
		/*----------2.1 使用iterator移除其内多个对象:不报错,数据正常 ------------*/
		/*Iterator<Person> iterator = list.iterator();
		while(iterator.hasNext()){
			System.out.println("list实施大小:"+list.size());
			Person person = iterator.next();
			iterator.remove();
		}*/
		
		/*----------2.2 使用iterator移除其内一个对象:不报错,数据正常 ------------*/
	/*	Iterator<Person> iterator = list.iterator();
		while(iterator.hasNext()){
			Person person = iterator.next();
			if(person.getName().equals("李四")){
				iterator.remove();
				break;
			}
		}*/
		
		
		/*----------3 使用iterator循环是时,修改数据: 正确不报错------------*/
		/*Iterator<Person> iterator = list.iterator();
		while(iterator.hasNext()){
			Person person = iterator.next();
			person.setName("lili");
		}
		
		Iterator<Person> iterator2 = list.iterator();
		while(iterator2.hasNext()){
			Person person2 = iterator2.next();
			System.out.println(person2.getName());
		}*/
		
		System.err.println("操作后list集合大小:"+list.size());
	}
}
class Person{
	private String name;
	private Integer id;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public Person(String name, Integer id) {
		super();
		this.name = name;
		this.id = id;
	}
}

 

### 解决方案概述 `ConcurrentModificationException` 是在 Java 编程中常见的异常之一,通常发生在尝试通过 `for-each` 循环或其他形式的集合遍历的同时修改集合的情况下。以下是几种有效的解决方案来避免此异常的发生。 --- #### 使用 Iterator 的 remove 方法 当使用 `Iterator` 遍历集合时,可以通过调用 `Iterator` 提供的 `remove()` 方法安全地移除元素。这是推荐的方式之一,因为它能够确保集合的一致性和线程安全性[^1]。 ```java import java.util.ArrayList; import java.util.Iterator; public class Example { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { Integer value = iterator.next(); if (value == 2) { iterator.remove(); // 安全删除 } } System.out.println(list); // 输出: [1, 3] } } ``` --- #### 创建临时副本进行操作 另一种常见做法是创建原始集合的一个副本,在副本上执行修改操作,从而避免直接对正在被遍历集合进行更改[^5]。 ```java import java.util.ArrayList; public class Example { public static void main(String[] args) { ArrayList<String> originalList = new ArrayList<>(); originalList.add("hello"); originalList.add("world"); originalList.add("java"); ArrayList<String> tempList = new ArrayList<>(originalList); // 复制列表 for (String item : tempList) { if ("world".equals(item)) { originalList.add("javaEE"); // 修改原列表 } } System.out.println(originalList); // 输出: [hello, world, java, javaEE] } } ``` 这种方法的优点在于可以完全隔离原始集合的操作逻辑,缺点则是可能带来额外的空间开销。 --- #### 利用并发集合类 对于多线程环境下的场景,建议采用支持高并发访问的数据结构,比如 `CopyOnWriteArrayList` 或者其他来自 `java.util.concurrent` 包中的实现[^4]。这些类内部实现了更复杂的同步机制以防止发生类似的冲突情况。 ```java import java.util.concurrent.CopyOnWriteArrayList; public class Example { public static void main(String[] args) { CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>(); list.add(1); list.add(2); list.add(3); for (Integer num : list) { if (num == 2) { list.remove(num); // 并发环境下允许的安全删除 } } System.out.println(list); // 输出: [1, 3] } } ``` 需要注意的是,虽然这种方式解决了 `ConcurrentModificationException`,但它可能会引入性能上的瓶颈,特别是在频繁写入的大规模数据集上。 --- #### 结合索引控制手动管理边界条件 如果不想依赖于高级工具,则可以直接利用传统的基于索引的 `for` 循环完成任务,并小心调整每次迭代后的指针位置[^3]。 ```java import java.util.ArrayList; public class Example { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); int size = list.size(); for (int i = 0; i < size; ) { if (list.get(i).intValue() == 2) { list.remove(i); size--; // 更新大小并保持当前下标不变 } else { i++; } } System.out.println(list); // 输出: [1, 3] } } ``` 这种技术相对灵活但也容易出错,因此仅适用于特定需求场合。 --- ### 总结 以上介绍了四种主要应对策略——借助 `Iterator` 接口、构建辅助容器、选用专用并发类型以及精细化手工编码。每种都有各自适用范围及局限性,请依据具体应用场景选取最合适的手段加以实施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值