在进行集合遍历操作删除或修改元素的时候会遇到一部分问题
遍历元素
// 遍历测试
@Test
void contextLoads() {
String[] array = {"1", "2", "3"};
for (String i : array) {
System.out.println(i);
}
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
for (String i : list) {
System.out.println(i);
}
}
1
2
3
111
222
333
再来看看编译后的源码(idea自带,在target包里打开类源码文件即可)
String[] array = new String[]{"1", "2", "3"};
String[] var2 = array;
int var3 = array.length;
for(int var4 = 0; var4 < var3; ++var4) {
String i = var2[var4];
System.out.println(i);
}
ArrayList<String> list = new ArrayList();
list.add("111");
list.add("222");
list.add("333");
Iterator var7 = list.iterator();
while(var7.hasNext()) {
String i = (String)var7.next();
System.out.println(i);
}
可见,遍历数组使用的是原始for循环,集合的话使用的是Iterator迭代器。
删除元素
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
System.out.println(list);
使用for循环
for (int i = 0; i <list.size(); i++) {
list.remove("222");
}
System.out.println(list);
[111, 222, 333]
[111, 333]
使用foreach
for (String i : list) {
list.remove("222");
}
System.out.println(list);
java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1095)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1049)
at com.demo.base.demo23.Demo23ApplicationTests.deleteTest(Demo23ApplicationTests.java:41)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
原因
迭代器内部的每次遍历都会记录List内部的modcount当做预期值,然后在每次循环中用预期值与List的成员变量modCount作比较,但是普通list.remove调用的是List的remove,这时modcount++,但是iterator内记录的预期值并没有变化,所以会报错。
如果想要删除元素的话需要使用迭代器内部的remove方法
Iterator<String> it = list.iterator();
while (it.hasNext()){
String next = it.next();
// if外使用list的remove方法还是会报错的
if(next.equals("222")){
it.remove();// 这里使用的是迭代器里面的remove()方法,
// 当然如果使用list的remove方法在此删除质地感元素的话是成功的,比如:list.remove("222")
}
}
System.out.println(list);
[111, 222, 333]
[111, 333]
上面的写法可以简化成lambda表达式
list.removeIf(next -> next.equals("222"));
修改元素
使用原始for
// 修改测试
@Test
void updateTest() {
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
System.out.println(list);
for (int i = 0; i <list.size(); i++) {
list.set(i,"444");
}
System.out.println(list);
}
[111, 222, 333]
[444, 444, 444]
可以修改元素
使用foreach
// 修改测试
@Test
void updateTest() {
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
System.out.println(list);
// for (int i = 0; i <list.size(); i++) {
// list.set(i,"444");
// }
for (String i : list) {
i="444";
}
System.out.println(list);
}
[111, 222, 333]
[111, 222, 333]
修改元素不行,修改元素的属性可不可以呢?
foreach修改元素属性
创建一个学生类
@Data
@AllArgsConstructor
@NoArgsConstructor
class Student {
private int age;
private String name;
}
接下来测试代码
@Test
void updateByElementTest() {
Student student=new Student(1,"huge");
Student student1=new Student(1,"xiaoyao");
List<Student> studentList=new ArrayList<>();
studentList.add(student);
studentList.add(student1);
System.out.println(student.getName());
System.out.println(student1.getName());
for(Student stu:studentList)
{
stu.setName("jingtian");
}
System.out.println(student.getName());
System.out.println(student1.getName());
}
huge
xiaoyao
jingtian
jingtian
修改不了对象,却可以修改对象的属性。
总结
- for与foreach都可以遍历数组/集合,不过for则在较复杂的循环中效率更高。
- foreach不可以删除/修改集合元素,而for可以
- foreach和for都可以修改元素里面的属性
所以相比较下来for循环更为灵活。
评论区