Java 集合(List、Set)遍历、判断、删除元素时的小陷阱
来源:互联网 发布:c语言脚本编写 编辑:程序博客网 时间:2024/06/07 04:03
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java!
开发中,常有场景:遍历集合,依次判断是否符合条件,如符合条件则删除当前元素。
不知不觉中,有些陷阱,不知你有没有犯。
一、漏网之鱼-for循环递增下标方式遍历集合,并删除元素
如果你用for循环递增下标方式遍历集合,在遍历过程中删除元素,你可能会遗漏了某些元素。说那么说可能也说不清楚,看以下示例:
import java.util.ArrayList;import java.util.List;public class ListTest_Unwork { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); System.out.println("Original list : " + list); String temp = null; for (int i = 0; i < list.size(); i++) { temp = list.get(i); System.out.println("Check for " + temp); if ("3".equals(temp)) { list.remove(temp); } } System.out.println("Removed list : " + list); }}
日志打印:
Original list : [1, 2, 3, 4, 5]Check for 1Check for 2Check for 3Check for 5Removed list : [1, 2, 4, 5]
如日志所见,其中值为4的元素并未经过判断,漏网之鱼。
解决方法为以下两个(但一般不建议我们在遍历中用不是遍历本身的函数删除元素,见下节关于“ConcurrentModificationException”的内容):
1、对于此情况,我一般都从后面开始遍历,以避免问题:
import java.util.ArrayList;import java.util.List;public class ListTest_Work { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); System.out.println("Original list : " + list); System.out.println(); String temp = null; for (int i = list.size() - 1; i >= 0; i--) { temp = list.get(i); System.out.println("Check for " + temp); if ("3".equals(temp)) { list.remove(temp); } } System.out.println("Removed list : " + list); }}
2、直接从新创建一个集合,重新摆放,但消耗内存,慎用:
import java.util.ArrayList;import java.util.List;public class ListTest_Work2 { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); System.out.println("Original list : " + list); System.out.println(); List<String> tempList = new ArrayList<String>(); for (String temp : list) { System.out.println("Check for " + temp); if (!"3".equals(temp)) { tempList.add(temp); } } System.out.println("Removed list : " + tempList); }}
二、ConcurrentModificationException异常-Iterator遍历集合过程中用其他手段(或其他线程)操作元素
ConcurrentModificationException是Java集合的一个快速报错(fail-fast)机制,防止多个线程同时修改同一个集合的元素。在用Iterator遍历集合时,如果你用其他手段(非Iterator自身手段)操作集合元素,就会报ConcurrentModificationException。
不信?用Iterator方式或简写的for(Object o : list) {}方式,遍历集合,修改元素时会报异常:
import java.util.ArrayList;import java.util.List;public class ListTest2_Unwork { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); System.out.println("Original list : " + list); System.out.println(); for (String temp : list) { System.out.println("Check for " + temp); if ("3".equals(temp)) { list.remove(temp); } } System.out.println("Removed list : " + list); }}
或
import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class ListTest3_Unwork { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); System.out.println("Original list : " + list); System.out.println(); Iterator<String> i = list.iterator(); String temp = null; while (i.hasNext()) { temp = i.next(); System.out.println("Check for " + temp); if ("3".equals(temp)) { list.remove(temp); } } System.out.println("Removed list : " + list); }}
日志:
Original list : [1, 2, 3, 4, 5]Check for 1Check for 2Check for 3Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831) at ListTest3_Unwork.main(ListTest3_Unwork.java:20)
在删除元素“3”时,会报异常。
对于此情况,需要用iterator的remove方法替代,结果是妥妥的:
import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class ListTest3_Work { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); System.out.println("Original list : " + list); System.out.println(); Iterator<String> i = list.iterator(); String temp = null; while (i.hasNext()) { temp = i.next(); System.out.println("Check for " + temp); if ("3".equals(temp)) { i.remove(); } } System.out.println("Removed list : " + list); }}
延伸个小问题,为什么for(Object o : list) {}方式遍历集合,现象和Iterator方式一样,都会报错呢?
答:这是因为Java的糖语法,“for(Object o : list) {}方式”只是Java语言用“易用性糖衣”吸引你的手段,本质上,它也是Iterator。不信,你写下下面这段程序,反编译看看就清楚了:
package com.nichagil.test.forloop;import java.util.ArrayList;import java.util.List;public class ForTester { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("a"); for (String s : list) { list.remove(s); System.out.println(s); } }}
反编译后是这样的:
package com.nichagil.test.forloop;import java.util.ArrayList;import java.util.Iterator;public class ForTester { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("a"); Iterator arg2 = list.iterator(); while (arg2.hasNext()) { String s = (String) arg2.next(); list.remove(s); System.out.println(s); } }}
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java!
- Java 集合(List、Set)遍历、判断、删除元素时的小陷阱
- 【Java】集合(List、Set、Map)遍历、删除、比较元素时的小陷阱
- java中循环遍历删除List和Set集合中元素的方法
- 编程技巧系列(2)Java 集合(List,Set,Map)遍历时有条件删除特定元素
- java 遍历 删除元素 List Set
- java 遍历 删除元素 List Set
- java 遍历list、set时 删除元素 java.util.ConcurrentModificationException
- JAVA遍历List集合并删除其中的元素
- Java遍历List集合并删除其中的元素
- Java 循环遍历删除set list中的元素
- Java删除List和Set集合中元素
- Java list集合通过遍历删除元素异常分析
- java ArrayList循环遍历并删除元素的常见陷阱
- JAVA中关于遍历List时删除元素的实践
- 遍历List集合同时删除元素的正确方法
- Java 集合List删除元素
- List、Set集合Map集合的遍历
- Java动态遍历List 时删除List特征元素
- 1.1 Generalized Linear Models 广义线性模型
- android app 很占内存
- Spring资源文件加载时classpath和classpath*的区别
- 【Opencv】Intel IPP下载安装测试
- (18)投影变换的定义和分类
- Java 集合(List、Set)遍历、判断、删除元素时的小陷阱
- 【J2EE核心开发学习笔记 002】线程基础
- 【J2EE核心开发学习笔记 003】网络基础
- 问题分析5步法
- PHP底层分析
- push本地代码到github出错
- padding
- Android新手,求推荐书籍自学!!!
- CentOS7中英文输入法及切换