`
暗黑小菠萝
  • 浏览: 46927 次
  • 性别: Icon_minigender_2
  • 来自: 大连
社区版块
存档分类
最新评论

ArrayList遍历删除陷阱

    博客分类:
  • Java
阅读更多
如何对ArrayList进行删除操作:

remove(int index);
remove(Object o);
removeAll(Collection<?> c);

用以上三个方法是可以正常使用的,但对ArrayList进行遍历删除元素时候需要格外注意:

List<String> testList = new ArrayList<String>();
testList.add("1");
testList.add("2");
testList.add("3");
testList.add("4");
testList.add("5");
testList.add("6");

分别采用三种方式遍历删除
①for循环
for(int i = 0 ; i < testList.size() ; i++){
	testList.remove(i);
}

for(String elem : testList){
	System.out.println(elem);
}

结果:


②foreach循环
for(String elem : testList){
	testList.remove(elem);
}

for(String elem : testList){
	System.out.println(elem);
}

结果:


③iterator循环
Iterator<String> it = testList.iterator();
while(it.hasNext()){
	it.next();
	it.remove();
}

for(String elem : testList){
	System.out.println(elem);
}

结果:空白(说明正常删除了全部元素)

下面对上面三种方式进行解析:
①for循环
因为for循环每次删除的是testList.remove(i);
当i=0;时testList.remove(0);删除掉了第一个元素,此时testList.size()大小为5。
当i=1;时testList.remove(1);删除掉此时testList中的第二个元素,略过了第一个元素。之后testList.size()大小为4。
当i=2;时testList.remove(2);删除掉此时testList中的第三个元素,略过了第1,2个元素。之后testList.size()大小为3。
当i=3;时i=testList.size(); for循环结束。所以并不能够完全删除掉整改ArrayList。
需要改写一下这个方法:
int length = testList.size();
for(int i = 0; i< length; i++){
	String t = testList.get(0);
	testList.remove(0);
}

此时就能够删除掉list的全部元素。

②foreach循环
java中的foreach循环其实就是根据list对象创建一个Iterator对象,用这个迭代对象来遍历testList,相当于list对象将元素的遍历托付给Iterator,如果要进行删除或者增加需要通过Iterator,直接对list进行删除时,Iterator会抛出ConcurrentModificationException异常
抛出异常的源码是:
final void checkForComodification() {
        if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
}

modCount是指这个list对象从new出来到现在被修改次数,当调用List的add或者remove方法的时候,这个modCount都会自动增减;
expectedModCount是指Iterator现在期望这个list被修改的次数是多少次。
iterator创建的时候modCount被赋值给了expectedModCount,但是调用list的add和remove方法的时候不会同时自动增减expectedModCount,这样就导致两个count不相等,从而抛出异常。

在ArrayList的所有涉及结构变化的方法中都增加modCount的值,包括:add()、remove()、addAll()、clear()等,这些方法每调用一次,modCount的值就加1。

③Iterator循环
因为是借助Iterator来删除list的元素,所以不会有问题,如果循环中使用list本身来删除同意会抛异常。


综上,推荐使用改进的第一种和第三种方式来迭代循环删除ArrayList
  • 大小: 8.5 KB
  • 大小: 23.3 KB
分享到:
评论

相关推荐

    java ArrayList.remove()的三种错误用法以及六种正确用法详解

    在for循环中直接删除元素可能导致遍历过程中的索引错乱。例如,当删除一个元素后,未更新的索引将指向下一个元素,但实际上,由于删除,这个位置已被前一个元素占用。例如: ```java List&lt;Long&gt; list = new ...

    突破程序员基本功的16课.part2

    3.3.3 ArrayList和LinkedList的性能分析和适用场景 3.4 Iterator迭代器 迭代时删除指定元素 3.5 小结 第4课 Java的内存回收 4.1 Java引用的种类 4.1.1 对象在内存中状态 4.1.2 强引用 4.1.3 软引用 4.1.4 ...

    java集合迭代器Iterator中的remove陷阱

    例如,在上面的代码中,对于`ArrayList`,删除"ccc"应该在检查到"bbb"之后进行。 ```java while(t.hasNext()){ String element = t.next(); if(element.equals("bbb")){ t.remove(); // 正确的删除时机 } } ```...

    避坑手册 - JAVA编码中容易踩坑的十大陷阱.doc

    当你需要在遍历List的同时删除元素时,直接使用for-each循环或者索引循环是错误的。这两种方式都会导致`ConcurrentModificationException`。正确的做法是使用迭代器(Iterator)进行删除,或者使用Java 8的Lambda...

    java集合框架全面进阶

    例如,了解HashMap的扩容机制、LinkedList的节点操作、ArrayList的动态数组管理等,能够帮助开发者在设计和实现自己的数据结构时避免常见陷阱。 6. **工具类**:Collections和Arrays类提供了很多实用的静态方法,如...

    java基础for循环练习题

    对于集合框架,如ArrayList、LinkedList等,增强型`for`循环是首选,它能简洁地遍历集合中的所有元素。如果需要对集合进行更复杂的操作,比如删除元素,则可能需要使用基本的`for`循环配合迭代器。 5. **其他用法*...

    很容易弄错的java面试题

    LinkedList则是双向链表,插入和删除操作更快,但遍历不如ArrayList效率高。 4. **多线程与并发**:深入理解synchronized关键字,包括可重入性、作用范围以及与volatile的关系。面试官可能会考察如何正确使用锁来...

    详解JAVA中的for-each循环与迭代

    例如,在上述代码中,我们创建了一个`ArrayList`并获取了一个迭代器,然后在`while`循环中尝试使用`list.remove()`删除元素,这违反了迭代器的规则,因此抛出了异常。正确做法是使用迭代器的`remove()`方法删除元素...

    Java开发人员最常犯的10个错误

    更简洁的方法是直接使用`Arrays.asList(arr).contains(targetValue)`或遍历数组进行比较,如`for(String s: arr){ if(s.equals(targetValue)) return true; } return false;`。 3. 在循环内部删除List元素: 在...

    Java Generics and Collections (Java泛型与集合)

    5. **集合的操作**:介绍迭代器、遍历、添加、删除、查找等基本操作。 6. **并发编程与集合**:如何在多线程环境中安全地使用集合,如ConcurrentHashMap和CopyOnWriteArrayList。 7. **集合性能优化**:选择合适的...

    超全Java集合框架讲解.md

    - **`ArrayList`**:基于动态数组实现,支持快速随机访问,但插入和删除操作相对较慢。 - **`LinkedList`**:基于双向链表实现,支持高效的插入和删除操作,但随机访问较慢。 #### `Queue`接口 - **`Deque`接口**...

    board-collection

    了解ArrayList和LinkedList的不同,比如ArrayList更适合随机访问,而LinkedList适合频繁插入和删除。 2. **Set接口**:学习HashSet和TreeSet的区别,HashSet基于HashMap,不保证元素顺序;TreeSet基于TreeMap,元素...

    一口气带你踩完五个 List 的大坑,真的是处处坑啊!

    理解 List 的这些常见陷阱对于编写健壮的 Java 代码至关重要。避免使用 `Arrays#asList` 直接转换数组到 List,除非你知道它不可变;在需要独立副本时,使用适当的构造函数创建新 List;注意不可变集合中的元素是否...

    java程序中容易出错的地方

    - **ArrayList vs LinkedList**:对于频繁插入删除的场景,应该选择`LinkedList`;而如果主要是元素的读取操作,则`ArrayList`更合适。 - **空指针异常**:在向集合中添加元素之前,务必检查该元素是否为null,以...

    35个Java代码性能优化总结.pdf

    ArrayList在随机访问时表现更佳,而LinkedList在插入和删除操作时更优。应根据实际情况选择合适的集合类型。 #### 4. I/O操作优化 在处理I/O操作时,应使用BufferedReader和BufferedWriter来减少对磁盘的读写次数,...

    Java基础训练源码

    源码可能涉及各种集合操作,如添加、删除、遍历和查找元素,以及集合间的转换。 5. **泛型**:泛型提供了一种在编译时确保类型安全的方式,防止在容器中存储不兼容的数据类型。源码将展示如何定义和使用泛型类、...

    详解JAVA高质量代码之数组与集合

    Arrays.asList返回的List是一个不可变的列表,这意味着它不支持添加、删除等修改操作。这是因为这个List是由Arrays类的一个静态内部类实现的,它继承自AbstractList,但没有实现可变操作。如果需要一个可变的List,...

    java_collection_source_code_analyze:Java集合部分源码分析-Source code collection

    例如,ArrayList的`add()`方法会检查容量并根据需要进行扩容,LinkedList的`remove()`方法则需要遍历链表找到目标节点。 - **哈希策略**:HashMap和HashSet依赖于对象的`hashCode()`方法来确定元素在内部数组中的...

    curso-dio-intro-collections

    了解每个类的特点和适用场景是十分重要的,例如,`ArrayList`适合快速随机访问,而`LinkedList`适合频繁插入和删除。 3. **泛型**:课程会强调泛型在集合中的应用,如何通过泛型来确保集合中存储的元素类型安全,...

Global site tag (gtag.js) - Google Analytics