目录
(1)迭代器遍历(2)增强for遍历编辑(3)Lambda表达式遍历
01. Java中的集合体系
Java中的集合分为两大类:
-
单列集合(collection):添加数据时,一次只添加一个数据。数据带有下标
-
双列集合(Map):在添加数据时,一次要添加一对数据;key和value(键值对)
02. 单列集合体系
单列集合起源于Collection接口,分为List集合和Set集合:
①List接口的三个实现类:ArrayList、LinkedList、Vector(现已弃用);
②List系列集合的特点有:有序、可重复、有索引
,有序是指存入的顺序和取出时的顺序是相同的;
③Set接口有两个实现类:HashSet、TreeSet;
④Set系列集合的特点有:无序、不可重复、无索引
,取数据时的顺序是随机的。
(1)单列集合顶层接口Collection
常用方法:
注意点:
1.添加元素 add 细节1: 如果我们要往List系列集合中添加数据, 那么方法永远返回true, 因为List系列的是允许元素重复的。 细节2: 如果我们要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功。 如果当前要添加的元素已经存在, 方法返回false,表示添加失败。因为Set系列的集合不允许重复。
2.删除 remove 细节1: 因为collection里面定义的是共性的方法, 所以此时不能通过索引 进行删除。 只能通过元素名称进行刷除。 细节2: 方法会有一个布尔类型的返回值, 删除成功返回true, 删除失败返回false,如果要除的元素不存在,就会删除失败。
4.判断元素是否包含 contain 细节:底层是依赖equals方法进行判断是否存在的。 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在java Bean类中,一定要重写equals方法
源码查看方法: 方法一:选中contains()方法,Ctrl+B跟进,进入到Collection接口中的源码; 方法二:选中contains()方法,右键,选择Go to --> implements 然后选择对应的实现类
1. Collection系列集合的遍历方式
(1)迭代器遍历
迭代器Iterator简介:
代码示例:
//1.创建集合并添加元素
Collection<String> coll = new ArrayList<>();
coll.add("一");
coll.add("二");
coll.add("三");
coll.add("四");
coll.add("五");
coll.add("六");
//2.通过集合获取迭代器,迭代器就好比一个箭头,刚获取时默认指向集合首个元素
Iterator it = coll.iterator();
while (it.hasNext()){
Object str = it.next();
System.out.println(str);
}
迭代器使用注意点:
-
当指针已经指向集合末尾时(如下图),继续调用next( )方法会报错误:NoSuchElementException
-
迭代器遍历完毕后,指针不会自动复位;下次再遍历时需要再创建一个迭代器对象。
-
在每次遍历中,next( )方法通常只调用一次,并用一个变量接收返回的元素;(因为每调用一次next( )方法,指针就会向后移动一位,所以每移动一次就要判断一下是否已经指向末尾了)
-
迭代器遍历时,不能用集合的方法进行增加或删除。否则会引发并发修改异常:ConcurrentModificationException
那么如何在遍历集合时删除集合中元素呢?方法如下:
使用Iterator.remove() 最安全和推荐的方法是使用迭代器的remove()方法,该方法专为遍历期间的安全删除设计。
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if ("B".equals(element)) {
iterator.remove();
}
}
System.out.println(list); // 输出: [A, C]
优点:不抛异常,适用于多种集合(List、Set等)。
缺点:代码较为冗长,需要显式使用迭代器。
原文链接:java中如何在集合遍历过程中删除元素(5种方法对比、案例、常见的错误及其后果)_java集合删除元素-CSDN博客
(2)增强for遍历
(小tips:在IDEA中快速打出增强for结构的写法:集合或数组名.for + Enter)
注意:增强for的底层是用迭代器实现的,在遍历时,也不能直接用集合的方法对元素进行增加或删除。否则会引发并发修改异常ConcurrentModificationException
(3)Lambda表达式遍历
示例代码 :
public static void main(String[] args) {
Collection<Object> coll = new ArrayList<>();
coll.add("张三");
coll.add("李四");
coll.add(456);
coll.add(789);
// for (Object o : coll) {
// System.out.println(o);
// }
//常规写法
coll.forEach(new Consumer<Object>() {
@Override
public void accept(Object o) {
System.out.println(o);
}
});
//结合Lambda表达式写法
coll.forEach((o) -> {
System.out.println(o);
});
//再次简化
coll.forEach(o->System.out.println(o));
//结合方法引用,且前后参数一样时,再次简化
coll.forEach(System.out::println);
}
03.List集合详解
由于篇幅过长,为方便大家浏览,这部分内容单独开了一片博客:
04.Set集合详解
05.总结
Collection系列集合使用场景:
集合的并发修改异常问题
-
当我们使用迭代器遍历集合,并删除集合中某些数据时程序就会报错;
(错误代码如下:)public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); list.add("王老二"); list.add("王五"); list.add("李逵"); list.add("李世华"); Iterator<String> it = list.iterator(); while (it.hasNext()){ String str = it.next(); if (str.contains("李")){ list.remove(str); } } }
程序报的异常:
Exception in thread "main" java.util.ConcurrentModificationException
如果我们不用迭代器,用普通for循环来进行相同操作也会有问题;
(错误示例代码:)
//用普通for循环来进行演示:
public static void main(String[] args) {
List<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 s = list.get(i);
if (s.contains("李")){
list.remove(s);
}
}
System.out.println("遍历后"+list);
输出结果:
遍历前:[张三, 李四, 李老二, 王五, 李逵, 李世华]
遍历后:[张三, 李老二, 王五, 李世华]
我们发现,程序并没有像我们预期的那样(将list集合内所有包含字符"李 "的元素删除掉);
①问题原因:
当第一次遍历到元素"李四"时,程序会成功删除;由于ArrayList底层是数组实现的,删除元素后,后面元素会向前移动,这就导致下一个元素(李老二)会移动到当前索引的位置;然后i++,直接越过了对"李老二"的判断。
因此,在遍历集合时,每删除当前元素,就会跳过下一个元素的判断;
②解决办法:
●普通for循环的解决办法
①每次移除完数据以后,执行一次i-- ,示例代码:
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.contains("李")){
list.remove(s);
i--;//移除完数据后,执行i--
}
}
②遍历时,改为从后往前遍历集合,示例代码:
for (int i = list.size()-1; i >= 0; i--) {
//从后往前倒序遍历集合
String s = list.get(i);
if (s.contains("李")){
list.remove(s);
}
}
●使用迭代器的解决办法:用迭代器自带的remove方法来删除元素
Iterator<String> it = list.iterator();
while (it.hasNext()){
String str = it.next();
if (str.contains("李")){
//list.remove(str);//会发生修改并发异常
it.remove();//底层也相当于执行了一次i--
}
}
最后,我们要注意:使用增强for 或 Lambda表达式的方法遍历时,也都会出现并发修改异常,且没有解决办法。
-
因为增强for的的底层就是迭代器实现的,增强for就是迭代器的简化写法