当前位置: 首页 > 科技观察

您还在编写自己的remove迭代器吗?快来看看新方法

时间:2023-03-16 02:23:28 科技观察

我们都知道List在循环的过程中不允许移除元素,为什么呢?普通新手可能会遇到这个问题,比如List遍历的过程中去掉数据,但是有几年开发经验的老手肯定不会这么做,很简单,会报错。Listremove我们可以看一段代码:publicstaticvoidmain(String[]args){Listlist=newArrayList<>();list.add("1");list.add("2");list.add("3");for(Strings:list){if(s.equals("1")){list.remove(s);}}System.out.println(list);}上面的代码一般是刚接触开发行业的小伙伴写的,但是运行起来会发现会报错。java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)在com.example的java.util.ArrayList$Itr.next(ArrayList.java:859)线程“主”java.util.ConcurrentModificationException中的异常。fastdfs.Test.main(Test.java:22)但是当我们改代码删除元素2时,发现又成功了!!!果然,成功了,看代码和运行结果:publicstaticvoidmain(String[]args){Listlist=newArrayList<>();list.add("1");list.add("2");list.add("3");for(Strings:list){if(s.equals("2")){list.remove(s);}}System.out.println(列表);}运行结果如下:为什么会这样?我删除不了第一个元素,但是删除第二个元素很容易,但是当我删除第三个元素时它不起作用。什么原因?这个时候我们就得看看他的源码编译了什么。源码如下:publicstaticvoidmain(String[]args){Listlist=newArrayList();list.add("1");list.add("2");list.add("3");迭代器var2=list.iterator();while(var2.hasNext()){Strings=(String)var2.next();如果(s.equals("3")){list.remove(s);}}System.out.println(列表);}也就是说,在foreach的循环内部,是迭代的形式,使用的核心方法是hasnext()和next()。既然使用了迭代器,为什么不呢?我们先看看迭代器的源码,再分析为什么不行。其实我们可以从报错中看到一些端倪。错误信息是ArrayList.java:909checkForComodification(){if(modCount!=expectedModCount)thrownewConcurrentModificationException();}源码在执行remove方法的时候,也会调用list中的remove方法。在源码中,这一段是:publicbooleanremove(Objecto){if(o==null){for(intindex=0;index0)System.arraycopy(elementData,index+1,elementData,index,numMoved);元素数据[--大小]=空;//明确让GC干活}这里我们有modCount++,当我们再次循环时,我们调用list内部类itr的next方法,当我们调用list的remove时,modCount++,我们的expectedModCount等于初始modCount值。这时候,当两者的值不相等时,就会出现异常。归根结底,虽然这个地方使用了iterator遍历,但是remove方法并不是iterator方法。那么当我们使用迭代器遍历然后移除时,它是什么样子的呢?publicstaticvoidmain(String[]args){Listlist=newArrayList<>();list.add("1");list.add("2");list.add("3");Iteratoriterator=list.iterator();while(iterator.hasNext()){Stringnext=iterator.next();if("3".equals(next)){iterator.remove();}}System.out.println(列表);}这样写是不是有点过分了,那我该如何快速写完这段代码呢?其实一行代码就能很快解决这个问题。先来看看代码怎么写:list.removeIf(vo->"3".equals(vo));不用关心返回值,只要能满足这个条件,那么就会从集合中移除。话不多说,来看结果:这样看,是不是觉得很简单,方便,快捷,而且如果说代码量,肯定是很少的,但是如果满足条件,就一定可以。remove的进阶玩法阿芬为什么说它是进阶玩法,其实并不是一个完整的进阶玩法。比如我们有这样一个功能,需要一个导入功能,那么导入的数据就只有一个车牌号是唯一的值。之前导入的数据将不会被处理。新添加的文件可能包含所有数据。数据库中已经存在的数据不做处理,然后导入数据库中不存在的数据。如果字段少,可能会有几种实现思路。第一种:mybatis的SelectKey标签,判断是否存在,存在则不添加。第二种方法:导入前先查询数据库数据,对比数据,然后直接移除,最后导入不存在的数据。这两种方法其实都可以实现,只是它们的应用条件不一样。如果字段是多少?如果自己写sql,成本有点高。如果你还是用Mybatis-plus,那好像第一种方法不能用了,只能用第二种方法了。那么我们的removeIf应该怎么写呢?//创建第一个UserListListuserList=newArrayList<>();用户user=newUser();user.setId(UUID.randomUUID().toString());user.setName("张三");user.setAge(20);user.setDept("开发部");userList.add(用户);用户user1=newUser();user1.setId(UUID.randomUUID().toString());user1.setName("李四");user1.setAge(22);user1.setDept("测试部门");userList.add(user1);用户user2=newUser();user2.setId(UUID.randomUUID().toString());user2.setName("王舞");user2.setAge(27);user2.setDept("财务部");userList.add(user2);//创建第二个UserListListuserEnd=newArrayList<>();用户user3=newUser();user3.setId(UUID.randomUUID().toString());user3.setName("张三");user3.setAge(20);user3.setDept("开发部");userEnd.add(user3);用户user4=new使用r();user4.setId(UUID.randomUUID().toString());user4.setName("李四");user4.setAge(22);user4.setDept("测试部门");userEnd.add(user4);如果这时候我们要将第一个userList中的数据导入到数据库中,userEnd就是数据库中的数据,这时候如果我们要根据名字区分,是不是要导入到王五中呢?这个时候我们就得把王舞的数据过滤掉,然后再导入。这时候removeIf就派上用场了。userList.removeIf(us1->userEnd.stream().anyMatch(u->us1.getName().equals(u.getName())));System.out.println(Arrays.toString(userList.toArray()));最后看一下结果:[User(id=029b0b0f-ad42-4c15-8341-a3bb401be6d6,name=王五,age=27,dept=财务部)]是不是已经搞定了?你学会了吗?