关于上个在foreach中ArrayList.Remove出错的解释

本文解析了在foreach循环中从ArrayList移除元素时引发的异常原因,并提供了一种高效解决方案——使用反向for循环。此外,还探讨了foreach语句的正确用法及其潜在风险。

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

关于上一篇中在foreach中Remove某一ArrayList的tiem会出错的问题,在网上搜了一下,发现这居然是一个臭名昭著的Collection问题,许多人第一次这样做的时候都中招了,现在将问题出现的原因及解决方法记录一下,确保以后不要再犯这种错误。

首先是foreach:
MSDN中的说明:foreach 语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach 语句用于循环访问集合以获取所需信息,但 不应用于更改集合内容以避免产生不可预知的副作用

其次是ArrayList.Remove:
当你remove第i个item时,第[i + 1, count)域中所有items的索引值皆减一(Array是连续的,要满足只要有k ∈ [0, count)则Array[k]必存在),那么当你在循环下一轮用i + 1为索引访问的即是原先list中索引为i + 2的那个item,由此可知,假设0号被删除时,原1号变为新0号,原2号变为新1号。。。下一轮访问的1号就是先前的2号,而原始的1号则永远没有被访问到 。

由上面的总结可以看出,这里出现 InvalidOperationException异常的原因应该是在foreach中更改了Collection集合内容的缘故,而不是我想象中的ArrayList发生了断链,尽管在foreach循环中会少访问一个item。

问题的解决方法有好多种,除了上一篇中我的解决方法外,还可以在foreach里面用Clone,for循环,ToArray……等等多种方法。
这里我选择用反向for循环方法来解决,因为这是几种方法中最高效的。修改上篇的代码为:
         public   void  DeleteOneUser( string  userSIPURI)
        
{
            
for (int i = userArray.Count; -->= 0; )
            
{
                
if (((PoCContactItem)userArray[i]).GetUserSipUri() == userSIPURI)
                
{
                    userArray.RemoveAt(i);
                }

            }

            RefeshSesonTreVw();
        }
程序运行正常。
反向for循环的方法非常简洁,推荐。


以上内容部分来自 http://blog.youkuaiyun.com/i_like_cpp/archive/2005/01/30/273843.aspx  
任务描述 本关任务:创建 ArrayList 集合并使用它的增删改查方法。 接收给定的一行字符串,实现如下需求: 1.通过空格(一个)切割字符串; 2.创建一个 ArrayList 集合; 3.将切割后的字符串元素添加至集合中; 4.删除集合的第一个和最后一个元素; 5.添加两个字符串:hello,educoder 至集合中; 6.修改集合的第三个元素,改为:list; 7.打印集合。 相关知识 List 集合 List 集合用于存储有序的、可以重复的元素,因此我们可以通过索引来访问、遍历元素。它主要有 ArrayList 和 LinkedList 两个实现类,本实训将介绍 ArrayList 集合。 ArrayList 集合 ArrayListList 集合的实现类,它的底层数据结构是数组,因此它具有查询快,增删慢的特点。 创建 ArrayList 集合 // 导入相关类 import java.util.ArrayList; import java.util.List; public class ExcTest { public static void main(String[] args) { // 创建ArrayList集合 List list=new ArrayList<String>(); } } 可以看到创建 ArrayList 集合时使用的是父类的引用指向子类对象,这种方式可以大大的提高程序的可扩展性。 ArrayList 集合的增删改查 增删改查示例: public static void main(String[] args) { // 创建ArrayList集合 List<String> list=new ArrayList<>(); // 使用add()方法增加元素 list.add("list"); // 在最新位置添加指定元素 list.add(1,"hello"); // 在指定位置添加元素 list.add(2,"java"); // 在指定位置添加元素 System.out.println(list); // 使用get()方法获取指定索引处元素,索引值从0开始 String s = list.get(0); System.out.println(s); // 使用set()方法修改指定索引位置的元素值 list.set(1,"hi"); System.out.println(list); // 使用remove()方法删除指定元素 list.remove(0); // 删除指定索引的元素 list.remove("hi"); // 删除指定元素 System.out.print(list); } 执行结果: [list, hello, java] list [list, hi, java] [java] 遍历 ArrayList 遍历集合有三种方式: 1.使用迭代器遍历; public static void main(String[] args) { // 创建ArrayList集合 List<String> list=new ArrayList<>(); // 使用add()方法添加元素 list.add("list"); list.add(1,"hello"); list.add(2,"java"); list.add("java"); // 通过迭代器遍历集合 Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } } 2.使用 foreach 遍历; public static void main(String[] args) { // 创建ArrayList集合 List<String> list=new ArrayList<>(); // 使用add()方法添加元素 list.add("list"); list.add(1,"hello"); list.add(2,"java"); list.add("java"); // 通过foreach遍历集合 for(String s:list){ System.out.println(s); } } 3.使用 size() 方法获取集合长度,配合 for 循环遍历集合。 public static void main(String[] args) { // 创建ArrayList集合 List<String> list=new ArrayList<>(); // 使用add()方法添加元素 list.add("list"); list.add(1,"hello"); list.add(2,"java"); list.add("java"); // 通过 size() 方法遍历集合 for(int x=0;x<list.size();x++){ System.out.println(list.get(x)); } } 以上三种方式执行结果: list hello java java 编程要求 仔细阅读右侧编辑区内给出的代码框架及注释,在 Begin-End 间编写程序代码,创建 ArrayList 集合并使用它的增删改查方法,具体要求如下: 接收给定的一行字符串(如:32 rfsd fwq g3r3qt t3q4t。); 通过空格(一个)切割字符串; 创建一个 ArrayList 集合; 将切割后的字符串元素添加至集合中; 删除集合的第一个和最后一个元素; 添加两个字符串:hello,educoder 至集合中; 修改集合的第三个元素,改为:list; 打印集合。 测试说明 平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。 例: 测试输入: 32 rfsd fwq g3r3qt t3q4t qt ta 预期输出: [rfsd, fwq, list, t3q4t, qt, hello, educoder]
03-13
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值