Collection集合的总结
1、如果希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据?
用ArrayList集合(有序、可重复、有索引),底层基于数组的。(常用)
2、如果希望记住元素的添加顺序,且增删首尾数据的情况较多?
用LinkedList集合(有序、可重复、有索引l),底层基于双链表实现的。
3、如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快?
用HashSet集合(无序,不重复,无索引),底层基于哈希表实现的。(常用)
4、如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快?
用LinkedHashSet集合(有序,不重复,无索引),底层基于哈希表和双链表。
5、如果要对元素进行排序,也没有重复元素需要存储?且希望增删改查都快?
用TreeSet集合,基于红黑树实现。
集合的并发修改异常问题
- 使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。
案例引入
通过一个小案例引入:
完成一个需求,找出集合中全部带“李”的名字,并从集合中删除。
使用迭代器实现
import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("王麻子"); list.add("小李子"); list.add("李爱花"); list.add("张全蛋"); list.add("晓李"); list.add("李玉强"); System.out.println(list); //需求:找出集合中全部带"李"的名字,并从集合中删除 Iterator<String> it = list.iterator(); while(it.hasNext()){ String name = it.next(); if(name.contains("李")){ list.remove(name); } } System.out.println(list); } }
运行结果:
使用for循环实现
import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("王麻子"); list.add("小李子"); list.add("李爱花"); list.add("张全蛋"); list.add("晓李"); list.add("李玉强"); System.out.println(list); //需求:找出集合中全部带"李"的名字,并从集合中删除 for(int i = 0;i < list.size();i++){ String name = list.get(i); if(name.contains("李")){ list.remove(name); } } System.out.println(list); } }
使用for循环来实现,每次遇到带“李” 的名字,删除之后索引++,会跳过一个元素的检查,极大概率导致漏删。
运行结果:
for循环-解决方法
每次检索到带“李”的名字,就把i再减一,使索引回到正确的位置;或者从后往前进行检索和删除。
import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("王麻子"); list.add("小李子"); list.add("李爱花"); list.add("张全蛋"); list.add("晓李"); list.add("李玉强"); System.out.println(list); //需求:找出集合中全部带"李"的名字,并从集合中删除 for(int i = 0;i < list.size();i++){ String name = list.get(i); if(name.contains("李")){ list.remove(name); i--; } } //或者倒着进行删除 System.out.println(list); } }
运行结果:
迭代器-解决方法
迭代器的解决方法就比较直接,我们在删除的时候就使用迭代器自己的删除方法就可以了:
import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("王麻子"); list.add("小李子"); list.add("李爱花"); list.add("张全蛋"); list.add("晓李"); list.add("李玉强"); System.out.println(list); //需求:找出集合中全部带"李"的名字,并从集合中删除 Iterator<String> it = list.iterator(); while(it.hasNext()){ String name = it.next(); if(name.contains("李")){ it.remove(); //删除迭代器当前遍历到的数据,每删除一个数据后,相当于也在底层做了i-- } } System.out.println(list); } }
运行结果也同样是:
注意:用增强for循环(foreach)遍历集合并删除数据,没有办法解决bug;同样,Lambda表达式也无法解决,因为其源代码也是使用foreach遍历的。
小结
- 由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常的错误。
怎么保证遍历集合同时删除数据时不出bug?
- 使用迭代器遍历集合,但用迭代器自己的删除方法删除数据即可。
- 如果能用for循环遍历时:可以倒着遍历并删除;或者从前往后遍历,但删除元素后做i--操作。
END