搜索

还在自己写迭代器进行remove?快来看看新方法

发表于 2025-11-04 00:14:43 来源:全栈开发

我们都知道 List 中是还自不允许在循环的过程中去进行移除元素的,为什么呢?己写一般的新人可能会遇到这个问题,比如说会从 List 的迭代遍历的过程中去进行 remove 数据,但是器进干过几年的开发的有经验的工作人员,是行r新方肯定不会这么干的,很简单,还自会报错。己写

List 进行 remove

我们可以来看一段代码:

复制public static void main(String[] args) { List<String> list= new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); for (String s: list) { if (s.equals("1")) { list.remove(s); } } System.out.println(list);}1.2.3.4.5.6.7.8.9.10.11.12.13.14.

上面这段代码,迭代一般都是器进初入开发行业的小伙伴可能会这么写,但是行r新方当你去运行的时候,就会发现会报一个错误。还自

复制Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList$Itr.next(ArrayList.java:859) at com.example.fastdfs.Test.main(Test.java:22)1.2.3.4.

但是己写当我们把代码改成删除元素 2 的时候,发现又成功了!迭代!器进!行r新方

高防服务器真的,成功了,我们看代码和运行结果:

复制public static void main(String[] args) { List<String> list= new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); for (String s: list) { if (s.equals("2")) { list.remove(s); } } System.out.println(list); }1.2.3.4.5.6.7.8.9.10.11.12.13.14.

运行结果如下:

为什么会出现这种情况,我删除第一个元素不行,删除第二个元素好用,删除第三个元素又不行了,到底是什么原因导致的呢?

这时候我们就得去看看他的源码编译出来是什么样子的。源码如下:

复制public static void main(String[] args) { List<String> list = new ArrayList(); list.add("1"); list.add("2"); list.add("3"); Iterator var2 = list.iterator(); while(var2.hasNext()) { String s = (String)var2.next(); if (s.equals("3")) { list.remove(s); } } System.out.println(list); }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.

也就是说,foreach 的循环内部,就是采用的iteratior形式,使用的核心方法是hasnext()和next()。

既然都使用迭代器了,为啥还是不行呢?我们来看看迭代器的源码,然后分析一下为啥不行.

其实我们可以从报错都能看出点端倪,报错信息是ArrayList.java:909 

复制checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }1.2.3.4.

源代码在执行 remove 方法的时候后,也是调用的IT技术网 list 当中的remove 方法,源代码中,就是这段:

复制public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.

中间调用的 fastRemove 方法中,中间就看到了:

复制 private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work }1.2.3.4.5.6.7.8.

这里我们的modCount++了

而当我们再一次循环的时候,调用的是list内部类itr的next方法,

在我们调用的list的remove的时候,modCount++了,而我们的expectedModCount是等于最开始modCount值.

这时候二者的值不相等的时候,就出现异常了。

归根结底,虽然这个地方使用的是迭代器的遍历,但是remove 的方法可不是迭代器的香港云服务器方法呀。

那么我们使用迭代器遍历然后移除是什么样子的呢?

复制 public static void main(String[] args) { List<String> list= new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String next = iterator.next(); if ("3".equals(next)){ iterator.remove(); } } System.out.println(list); }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.

这么写是不是有点多,那么应该如何快速的写完这段代码呢?

其实一行代码就能很快解决这个事情,我们先来看代码怎么写的:

复制list.removeIf(vo-> "3".equals(vo));1.

也不用管返回值了,只要是能满足这个条件的 ,那么就会从集合中给移除掉。

话不多说,看结果:

这么一看,是不是发现非常简单方便,而且还快捷,而且如果要是对于代码量来说的话,那肯定是非常的少的,但凡满足条件的,肯定可以。

removeIf 的进阶玩法

阿粉为什么称之为进阶玩法,实际上也并不是完整的进阶玩法,比如说如果我们有一个功能是这样的,要求做一个导入的功能,然后导入的数据只有一个车牌号是唯一值,之前导入的数据,不做处理,新增的文件中,可能会包含所有的数据,要求数据库中已经存在的数据,不处理,然后导入数据库中不存在的数据。

如果字段少的话,那么实现思路可能会有几种。

第一种:

mybatis 的 SelectKey 标签,判断是否存在,如果存在就不进行新增。

第二种:

导入之前,查询数据库数据,比对数据,然后直接进行remove,最后不存在的数据导入

这两种方法实际上都能实现,但是他们的适用情况就不太一样了,如果字段非常多呢?

自己写sql 的话,那么代价实在是有点大,如果你们使用的还是 Mybatis-plus 的话,那么肯定第一种方式好像就没办法使用了,只能使用第二种了。

那么我们的 removeIf 应该怎么来写呢?

复制 //

创建第一个UserList

List<User> userList = new ArrayList<>(); User user = new User(); user.setId(UUID.randomUUID().toString()); user.setName("张三"); user.setAge(20); user.setDept("开发部"); userList.add(user); User user1 = new User(); user1.setId(UUID.randomUUID().toString()); user1.setName("李四"); user1.setAge(22); user1.setDept("测试部"); userList.add(user1); User user2 = new User(); user2.setId(UUID.randomUUID().toString()); user2.setName("王五"); user2.setAge(27); user2.setDept("财务部"); userList.add(user2);//

创建第二个UserList

List<User> userEnd= new ArrayList<>(); User user3= new User(); user3.setId(UUID.randomUUID().toString()); user3.setName("张三"); user3.setAge(20); user3.setDept("开发部"); userEnd.add(user3); User user4= new User(); user4.setId(UUID.randomUUID().toString()); user4.setName("李四"); user4.setAge(22); user4.setDept("测试部"); userEnd.add(user4);1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.

如果我们这时候要把第一个userList 中的数据导入数据库,而 userEnd 则是数据库中的数据,这时候,我们要根据姓名来区分的话,是不是应该之导入王五才对,这时候我们得筛选出王五的数据来,然后做导入,这个时候 removeIf 就派上用场了。

复制 userList.removeIf(us1-> userEnd.stream().anyMatch(u -

>us1.getName().equals(u.getName())));

System.out.println(Arrays.toString(userList.toArray()));1.2.3.

我们最后来看看结果:

复制[User(id=029b0b0f-ad42-4c15-8341-a3bb401be6d6, name=王五, age=27, dept=财务部)]1.

是不是已经做到了呢?

你学会了么?

随机为您推荐
版权声明:本站资源均来自互联网,如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

Copyright © 2016 Powered by 还在自己写迭代器进行remove?快来看看新方法,全栈开发  滇ICP备2023006006号-32sitemap

回顶部