JAVA中简单的for循环居然有这么多坑
发布时间:2023-04-15 11:16:43 所属栏目:教程 来源:
导读:foreach循环剔除方式
很多新手的第一想法就是for循环逐个判断校验下然后符合条件的剔除掉就行了嘛~ so easy...
1分钟就把代码写完了:
public List<UserDetail> filterallDevDeptUsers(List<UserDetail> allU
很多新手的第一想法就是for循环逐个判断校验下然后符合条件的剔除掉就行了嘛~ so easy...
1分钟就把代码写完了:
public List<UserDetail> filterallDevDeptUsers(List<UserDetail> allU
|
foreach循环剔除方式 很多新手的第一想法就是for循环逐个判断校验下然后符合条件的剔除掉就行了嘛~ so easy... 1分钟就把代码写完了: public List<UserDetail> filterallDevDeptUsers(List<UserDetail> allUsers) { for (UserDetail user : allUsers) { // 判断部门如果属于dev,则直接剔除 if ("dev".equals(user.getDepartment())) { allUsers.remove(user); } } // 返回剩余的用户数据 return allUsers; } 然后信心满满的点击了执行按钮: java.util.ConcurrentModificationException: null at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList$Itr.next(ArrayList.java:859) at com.veezean.demo4.UserService.filterallDevDeptUsers(UserService.java:13) at com.veezean.demo4.Main.main(Main.java:26) 诶? what are you 弄啥嘞?咋抛异常了? 一不留神就踩坑里了,下面就一起分析下为啥会抛异常。 原因分析: JAVA的foreach语法实际处理是基于迭代器Iterator进行实现的。 在循环开始时,会首先创建一个迭代实例,这个迭代实例的expectedModCount 赋值为集合的modCount。而每当迭代器使⽤ hashNext() / next() 遍历下⼀个元素之前,都会检测 modCount 变量与expectedModCount 值是否相等,相等的话就返回遍历;否则就抛出异常ConcurrentModificationException,终⽌遍历。 如果在循环中添加或删除元素,是直接调用集合的add(),remove()方法,导致了modCount增加或减少,但这些方法不会修改迭代实例中的expectedModCount,导致在迭代实例中expectedModCount与 modCount的值不相等,抛出ConcurrentModificationException异常。 下标循环操作 嗯哼?既然foreach方式不行,那就用原始的下标循环的方式来搞,总不会报错了吧?依旧很easy ... public List<UserDetail> filterallDevDeptUsers(List<UserDetail> allUsers) { for (int i = 0; i < allUsers.size(); i++) { // 判断部门如果属于dev,则直接剔除 if ("dev".equals(allUsers.get(i).getDepartment())) { allUsers.remove(i); } } // 返回剩余的用户数据 return allUsers; } 代码一气呵成,执行一下,看下处理后的输出: {id=2, name='李四', department='dev'} {id=3, name='王五', department='product'} {id=4, name='铁柱', department='pm'} 果然,不报错了,结果也输出了,完美~ 等等?这样真的OK了吗?我们的代码逻辑里面是判断如果"dev".equals(department),但是输出结果里面,为啥还是有department=dev这种本应被剔除掉的数据呢? 这里如果是在真实业务项目中,开发阶段不报错,又没有仔细去验证结果的情况下,流到生产线上,就可能造成业务逻辑的异常。 接下来看下出现这个现象的具体原因。 原因分析: 我们知道,list中的元素与下标之间,其实并没有强绑定关系,仅仅只是一个位置顺序的对应关系,list中元素变更之后,其每个元素对应的下标都可能会变更,如下示意: 那么,从List中删除元素之后,List中被删元素后面的所有元素下标都发生前移,但是for循环的指针i是始终往后累加的,再处理下一个的时候,就可能会有部分元素被漏掉没有处理。 所以到这里呢,也就可以知道为啥上面的代码执行后会出现漏网之鱼啦~ 正确方式 见识了上面2个坑操作之后,那正确妥当的操作方式应该是怎么样的呢? 迭代器方式 诶?没搞错吧?前面不是刚说过foreach方式也是使用的迭代器,但是其实是坑操作吗?这里怎么又说迭代器模式是正确方式呢? 虽然都是基于迭代器,但是使用逻辑是不一样的,看下代码: public List<UserDetail> filterallDevDeptUsers(List<UserDetail> allUsers) { Iterator<UserDetail> iterator = allUsers.iterator(); while (iterator.hasNext()) { // 判断部门如果属于dev,则直接剔除 if ("dev".equals(iterator.next().getDepartment())) { // 这是重点,此处操作的是Iterator,而不是list iterator.remove(); } } // 返回剩余的用户数据 return allUsers; } 执行结果: {id=3, name='王五', department='product'} {id=4, name='铁柱', department='pm'} (编辑:汽车网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
推荐文章
站长推荐
