我是靠谱客的博主 顺心大雁,最近开发中收集的这篇文章主要介绍java常见小错误(二):Java迭代器iterator和for循环的区别java常见小错误(二):Java迭代器iterator和for循环的区别一、常见错误二、错误原因三、foreach和Iterator的关系四、讨论一下集合遍历的常见问题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

java常见小错误(二):Java迭代器iterator和for循环的区别

java常见错误系列文章
下一篇:java常见小错误(一):变量类型自动转换与强制转换
往期文章推荐:
  java小技巧(三):JAVA 交集,差集,并集
  java小技巧(二):进制转换


【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权);
本博客的内容来自于:java常见小错误(二):Java迭代器iterator和for循环的区别;
学习、合作与交流联系q384660495;
本博客的内容仅供学习与参考,并非营利;


文章目录

  • java常见小错误(二):Java迭代器iterator和for循环的区别
  • 一、常见错误
  • 二、错误原因
  • 三、foreach和Iterator的关系
  • 四、讨论一下集合遍历的常见问题
    • 1、for循环的侧漏现象
    • 2、可以直接使用迭代器(会修改expectedModCount (期望集合修改次数))
    • 3、可以使用java 8的新特性filter过滤不要的元素
    • 4、foreach也可以,但是限制条件很多


一、常见错误

在Iterator迭代器迭代过程或者foreach循环中,调用Collection的remove(obj)方法,要么会报错(并发修改的错误),要么行为不确定。
常见异常

二、错误原因

foreach底层也是使用了iterator的方法。foreach反编译结果如下:
反编译结果
fail-fast,即快速失败,它是Java集合的一种错误检测机制。 当多个线程对集合(非fail-safe的集合类)进行结构上的改变的操作时,有可能会产生fail-fast机制,这个时候就会抛出ConcurrentModificationException(当方法检测到对象的并发修改,但不允许这种修改时就抛出该异常)。

同时需要注意的是,即使不是多线程环境,如果单线程违反了规则,同样也有可能会抛出改异常。

那这又和foreach循环有什么关系呢?
上文分析到了,foreach的底层是迭代器实现的,由debug发现,在迭代器中使用Iterator.next 会调用 Iterator.checkForComodification方法 ,而异常就是checkForComodification方法中抛出的。

我们直接看下checkForComodification方法的代码,看下抛出异常的原因:
异常

  • modCount是ArrayList中的一个成员变量。它表示该集合实际被修改的次数。

  • expectedModCount 是 ArrayList中的一个内部类——Itr中的成员变量。expectedModCount表示这个迭代器期望该集合被修改的次数。其值是在ArrayList.iterator方法被调用的时候初始化的。只有通过迭代器对集合进行操作,该值才会改变。

  • Itr是一个Iterator的实现,使用ArrayList.iterator方法可以获取到的迭代器就是Itr类的实例。

他们之间关系:
关系

由上图可知,迭代器开始遍历之前该迭代器的expectedModCount (期望集合修改次数)已经被modCount(实际修改次数)赋值了,然而在foreach遍历中删除数据或添加数据都是对modCount(实际修改次数)的修改,又因为是调用集合类自己的方法,所以不会对expectedModCount (期望集合修改次数)进行修改(这就导致iterator在遍历的时候,会发现有一个元素在自己不知不觉的情况下就被删除或添加了),所以就造成了不等的情况,所以就会抛出一个java.util.ConcurrentModificationException(修改并发异常),用来提示用户,可能发生了并发修改。

总之,我们不能在本线程或其他线程再调用Collection的add,remove等方法来修改集合。 要保证遍历数据的稳定性。

三、foreach和Iterator的关系

for each以用来处理集合中的每个元素而不用考虑集合定下标。就是为了让用Iterator简单。但是删除的时候,区别就是在remove,循环中调用集合remove会导致原集合变化导致错误,而应该用迭代器的remove方法。

使用for循环还是迭代器Iterator对比

  • 采用ArrayList对随机访问比较快,而for循环中的get()方法,采用的即是随机访问的方法,因此在ArrayList里,for循环较快
  • 采用LinkedList则是顺序访问比较快,iterator中的next()方法,采用的即是顺序访问的方法,因此在LinkedList里,使用iterator较快
  • 从数据结构角度分析,for循环适合访问顺序结构,可以根据下标快速获取指定元素.而Iterator 适合访问链式结构,因为迭代器是通过next()和Pre()来定位的.可以访问没有顺序的集合.
  • 而使用 Iterator 的好处在于可以使用相同方式去遍历集合中元素,而不用考虑集合类的内部实现(只要它实现了 java.lang.Iterable 接口),如果使用 Iterator 来遍历集合中元素,一旦不再使用 List 转而使用 Set 来组织数据,那遍历元素的代码不用做任何修改,如果使用 for 来遍历,那所有遍历此集合的算法都得做相应调整,因为List有序,Set无序,结构不同,他们的访问算法也不一样.(还是说明了一点遍历和集合本身分离了)

四、讨论一下集合遍历的常见问题

1、for循环的侧漏现象

代码如下:
侧漏

结果:
结果
由上图可知我要删除集合中的chengxi,但是删除后还有,这就是漏删了,那这又是为什呢?

因为普通for循环是根据索引删除的,由于两个相同值在相邻的位置,当删除第一个值之后,集合发生改变要重新排序索引(因为集合发生改变他的的底层**Object[]**要做位移操作,这里是要向前位移一个索引),所以后面那个要被删除的值就被挪到了删除值的索引位置,从而避免了删除也就造成了漏删。

当然也可以解决,在每次删除值的时候让索引自减就好了,最好是倒序遍历,还有equals方法也要倒着写防止空指针。

2、可以直接使用迭代器(会修改expectedModCount (期望集合修改次数))


// 迭代器循环遍历
List<String> stringListFor = getStringList();
System.out.println("删之前:"+stringListFor);
Iterator<String> iterator = stringListFor.iterator();
while (iterator.hasNext()){
if(iterator.next().equals("chengxi")){
iterator.remove();
}
}

3、可以使用java 8的新特性filter过滤不要的元素


// java 8新特性filter循环遍历
List<String> stringListFor = getStringList();
System.out.println("删之前:"+stringListFor);
List<String> stringList8 = stringListFor.stream().filter(s -> !s.equals("chengxi")).collect(Collectors.toList());
System.out.println("删之后:"+stringList8);

4、foreach也可以,但是限制条件很多

首先你很明确只删除一个元素,而且删除之后就直接结束循环,避免下一次使用Iterator.next就不会抛出异常了。


//增强for循环遍历
List<String> stringListForeach = getStringList();
System.out.println("遍历之前"+stringListForeach);
for (String s:stringListForeach) {
if(s.equals("程熙")){
stringListForeach.remove(s);
}
//删除后就结束遍历,避免抛异常
break;
}
System.out.println("遍历之后"+stringListForeach);

最后

以上就是顺心大雁为你收集整理的java常见小错误(二):Java迭代器iterator和for循环的区别java常见小错误(二):Java迭代器iterator和for循环的区别一、常见错误二、错误原因三、foreach和Iterator的关系四、讨论一下集合遍历的常见问题的全部内容,希望文章能够帮你解决java常见小错误(二):Java迭代器iterator和for循环的区别java常见小错误(二):Java迭代器iterator和for循环的区别一、常见错误二、错误原因三、foreach和Iterator的关系四、讨论一下集合遍历的常见问题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部