Java 基础集合遍历删除 for与foreach区别

来源:互联网 发布:淘宝买手机靠谱吗 编辑:程序博客网 时间:2024/06/01 23:32

   在日常Java 开发中,想要在遍历中删除一个集合中的元素,这是很常见的,但是如果用法不当,那么就会导致系统存在一些隐式bug ! 笔者今天拿list 举例来分析一下,Java 中集合应如何正确删除.

1. 错误删除方式示例:

    1.1 在for each 循环体中遍历删除

[java] view plain copy
  1. /** 不可行方案一:  for each 循环删除方式 
  2.  *  会抛出异常:ConcurrentModificationException,表示当前迭代对象不能修改 
  3.  */  
  4. @Test(expected=java.util.ConcurrentModificationException.class)  
  5. public void test_clear_error_1(){  
  6.     List<String> list = creatStringList();  
  7.     for (String str : list) {  
  8.         list.remove(str);  
  9.     }  
  10. }  

    1.2. for 循环 正序遍历删除

[java] view plain copy
  1. /** 不可行方案二:  for 循环正序删除法 
  2.  *  此中方式不会报运行错误,但是会有逻辑错误,因为没删除一个元素list.size()都在改变, 
  3.  *  所以结果会少删除元素,循环的总次数并不是list.size() 
  4.  */  
  5. @Test  
  6. public void test_clear_error_2(){  
  7.     List<String> list = creatStringList();  
  8.     for(int i=0; i<list.size(); i++){  
  9.         list.remove(i);  
  10.     }  
  11.     System.out.println(list);  
  12. }  

   1.3. for 循环正序遍历删除2

[java] view plain copy
  1. /** 不可行方案三:  for 循环正序删除法 -- list长度使用变量保存 
  2.  *  会报数组下标越界异常, 因为list的长度在动态减少 
  3.  */  
  4. @Test(expected=java.lang.IndexOutOfBoundsException.class)  
  5. public void test_clear_error_3(){  
  6.     List<String> list = creatStringList();  
  7.     int length = list.size();  
  8.     for(int i=0; i<length; i++){  
  9.         list.remove(i);  
  10.     }  
  11.     System.out.println(list);  
  12. }  

2. 正确删除方案

    1. for 循环遍历删除

[java] view plain copy
  1. /** 可行方案一:  for 循环倒序删除法  
  2.  *  性能最高 
  3.  * */  
  4. @Test  
  5. public void test_clear_right_1(){  
  6.     List<String> list = creatStringList();  
  7.     for(int i=list.size() -1 ; i>=0; i--){  
  8.         list.remove(i);  
  9.     }  
  10.     System.out.println(list);  
  11. }  

    2. iterator 迭代删除

[java] view plain copy
  1. /** 可行方案二: iterator 变量删除 */  
  2. @Test  
  3. public void test_clear_right_2(){  
  4.     List<String> list = creatStringList();  
  5.     Iterator<String> iterator = list.iterator();  
  6.     while(iterator.hasNext()){  
  7.         iterator.remove();  
  8.     }  
  9.     System.out.println(list);  
  10. }  

    3. removeAll 删除

[java] view plain copy
  1. /** 可行方案三: removeAll()  
  2.  *  写法最简单,性能最差,可查看源代码:  
  3.  *  java.util.ArrayList.batchRemove(Collection<?> c, boolean complement) 
  4.  */  
  5. @Test  
  6. public void test_clear_right_3(){  
  7.     List<String> list = creatStringList();  
  8.     list.removeAll(list);  
  9.     System.out.println(list);  
  10. }  

3. 总结

    1. 在删除set , collection 时也是一样的,推荐使用倒序删除方法.

    2. 在只需要删除一个元素的时候,for 循环正序删除也可以实现,但是在一次for 循环中删除多个的话,就会出现问题.所以建议在删除一个元素的时候,也使用倒序删除法.




如何正确遍历删除List中的元素,你会吗?

遍历删除List中的元素有很多种方法,当运用不当的时候就会产生问题。下面主要看看以下几种遍历删除List中元素的形式:

1.通过增强的for循环删除符合条件的多个元素

2.通过增强的for循环删除符合条件的一个元素

3.通过普通的for删除删除符合条件的多个元素

4.通过Iterator进行遍历删除符合条件的多个元素

 

[java] view plain copy
  1. /**  
  2.  * 使用增强的for循环  
  3.  * 在循环过程中从List中删除非基本数据类型以后,继续循环List时会报ConcurrentModificationException  
  4.  */    
  5. public void listRemove() {    
  6.     List<Student> students = this.getStudents();    
  7.     for (Student stu : students) {    
  8.         if (stu.getId() == 2)     
  9.             students.remove(stu);    
  10.     }    
  11. }    
[java] view plain copy
  1. /**  
  2.  * 像这种使用增强的for循环对List进行遍历删除,但删除之后马上就跳出的也不会出现异常  
  3.  */    
  4. public void listRemoveBreak() {    
  5.     List<Student> students = this.getStudents();    
  6.     for (Student stu : students) {    
  7.         if (stu.getId() == 2) {    
  8.             students.remove(stu);    
  9.             break;    
  10.         }    
  11.     }    
  12. }    
[java] view plain copy
  1. /**  
  2.  * 这种不使用增强的for循环的也可以正常删除和遍历,  
  3.  * 这里所谓的正常是指它不会报异常,但是删除后得到的  
  4.  * 数据不一定是正确的,这主要是因为删除元素后,被删除元素后  
  5.  * 的元素索引发生了变化。假设被遍历list中共有10个元素,当  
  6.  * 删除了第3个元素后,第4个元素就变成了第3个元素了,第5个就变成  
  7.  * 了第4个了,但是程序下一步循环到的索引是第4个,  
  8.  * 这时候取到的就是原本的第5个元素了。  
  9.  */    
  10. public void listRemove2() {    
  11.     List<Student> students = this.getStudents();    
  12.     for (int i=0; i<students.size(); i++) {    
  13.         if (students.get(i).getId()%3 == 0) {    
  14.             Student student = students.get(i);    
  15.             students.remove(student);    
  16.         }    
  17.     }    
  18. }    

[java] view plain copy
  1. /**  
  2.  * 使用Iterator的方式可以顺利删除和遍历  
  3.  */    
  4. public void iteratorRemove() {    
  5.     List<Student> students = this.getStudents();    
  6.     System.out.println(students);    
  7.     Iterator<Student> stuIter = students.iterator();    
  8.     while (stuIter.hasNext()) {    
  9.         Student student = stuIter.next();    
  10.         if (student.getId() % 2 == 0)    
  11.             stuIter.remove();//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException    
  12.     }    
  13.     System.out.println(students);    
  14. }    

for与foreach区别 参见

http://blog.csdn.net/heyuchang666/article/details/49683615

http://blog.csdn.net/u010031673/article/details/51800339

1、使用foreach来遍历集合时,集合必须实现Iterator接口,foreach就是使用Iterator接口来实现对集合的遍历的
2、在用foreach循环遍历一个集合时不能向集合中增加元素,不能从集合中删除元素,否则会抛出ConcurrentModificationException异常。抛出该异常是因为在集合内部有一个modCount变量用于记录集合中元素的个数,当向集合中增加或删除元素时,modCount也会随之变化,在遍历开始时会记录modCount的值,每次遍历元素时都会判断该变量是否发生了变化,如果发生了变化则抛出ConcurrentModificationException异常

原创粉丝点击