在学习java中的collection时注意到,collection层次的根接口Collection实现了Iterable接口(位于java.lang包中),实现这个接口允许对象成为 "foreach" 语句的目标,而此接口中的唯一方法,实现的就是返回一个在一组 T 类型的元素上进行迭代的迭代器。

一、迭代器Iterator

接口:Iterator

1 public interface Iterator{2

3 boolean hasNext();4

5 E next();6

7 voidremove();8 }

查看Iterator接口API可以知道,这是对collection进行迭代的迭代器。迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。

尤其值得注意的是此迭代器remove()方法的使用:从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法(remove方法)之外的其他方式修改了该迭代器所指向的 collection,则迭代器的行为是不确定的。接口设计人员在设计Iterator接口的时候已经指出,在进行迭代时如果调用了除了迭代器的remove()方法修改了该迭代器所指向的collection,则会造成不确定的后果。具体出现什么后果依迭代器的具体实现而定。针对这种不确定的后果可能出现的情况,在学习ArrayList时遇到了其中一种:迭代器抛出 ConcurrentModificationException异常。具体异常情况如下代码所示:

1 importjava.util.ArrayList;2 importjava.util.Collection;3 importjava.util.Iterator;4

5 public classItaratorTest {6

7 public static voidmain(String[] args) {8 Collection list = new ArrayList();9 list.add("Android");10 list.add("IOS");11 list.add("Windows Mobile");12

13 Iterator iterator =list.iterator();14 while(iterator.hasNext()) {15 String lang =iterator.next();16 list.remove(lang);//will throw ConcurrentModificationException17 }18 }19

20 }

此段代码在运行时会抛出ConcurrentModificationException异常,因为我们在迭代器运行期间没有用iterator的remove()方法来删除元素,而是使用ArrayList的 remove()方法改变了迭代器所指向的collection。这就违反了迭代器的设计原则,所以发生了异常。

所报异常情况如下所示:

Exception in thread "main"java.util.ConcurrentModificationException

at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)

at java.util.ArrayList$Itr.next(ArrayList.java:831)

at Text.ItaratorTest.main(ItaratorTest.java:17)

二、for-each循环与迭代器Iterator

从Java5起,在Java中有了for-each循环,可以用来循环遍历collection和array。Foreach循环允许你在无需保持传统for循环中的索引,或在使用iterator /ListIterator(ArrayList中的一种迭代器实现)时无需调用while循环中的hasNext()方法就能遍历collection。for-each循环简化了任何Collection或array的遍历过程。但是使用foreach循环也有两点需要注意。

使用foreach循环的对象,必须实现了Iterable接口

请看如下示例:

1 importjava.util.ArrayList;2

3 public classForeachTest1 {4

5 public static voidmain(String args[]) {6 CustomCollection myCollection = new CustomCollection();7 myCollection.add("Java");8 myCollection.add("Scala");9 myCollection.add("Groovy");10

11 //What does this code will do, print language, throw exception or12 //compile time error

13 for(String language : myCollection) {14 System.out.println(language);15 }16 }17

18 private class CustomCollection{19 private ArrayListbucket;20

21 publicCustomCollection() {22 bucket = newArrayList();23 }24

25 public intsize() {26 returnbucket.size();27 }28

29 public booleanisEmpty() {30 returnbucket.isEmpty();31 }32

33 public booleancontains(T o) {34 returnbucket.contains(o);35 }36

37 public booleanadd(T e) {38 returnbucket.add(e);39 }40

41 public booleanremove(T o) {42 returnbucket.remove(o);43 }44

45 }46 }

上述代码将无法通过编译,这是因为代码中的CustomCollection类没有实现Iterable接口,编译期的报错如下:

Exception in thread "main"java.lang.Error: Unresolved compilation problem:

Can only iterate over an array or an instance of java.lang.Iterable

at Text.ForeachTest1.main(ForeachTest1.java:15)

事实上,无需等到编译时才发现报错,eclipse会在这段代码写完之后就会在foreach循环处显示错误:Can only iterate over an array or an instance of java.lang.Iterable

从上述示例可以再次得到确认的是,foreach循环只适用于实现了Iterable接口的对象。由于所有内置Collection类都实现了java.util.Collection接口,已经继承了Iterable,所以为了解决上述问题,可以选择简单地让CustomCollection实现Collection接口或者继承AbstractCollection。解决方式如下:

1 importjava.util.AbstractCollection;2 importjava.util.ArrayList;3 importjava.util.Iterator;4

5 public classForeachTest {6 public static voidmain(String args[]) {7 CustomCollection myCollection = new CustomCollection();8 myCollection.add("Java");9 myCollection.add("Scala");10 myCollection.add("Groovy");11 for(String language : myCollection) {12 System.out.println(language);13 }14 }15

16 private static class CustomCollection extends AbstractCollection{17 private ArrayListbucket;18

19 publicCustomCollection() {20 bucket = newArrayList();21 }22

23 public intsize() {24 returnbucket.size();25 }26

27 public booleanisEmpty() {28 returnbucket.isEmpty();29 }30

31 public booleancontains(Object o) {32 returnbucket.contains(o);33 }34

35 public booleanadd(T e) {36 returnbucket.add(e);37 }38

39 public booleanremove(Object o) {40 returnbucket.remove(o);41 }42

43 @Override44 public Iteratoriterator() {45 //TODO Auto-generated method stub

46 returnbucket.iterator();47 }48 }49 }

2.foreach循环的内部实现也是依靠Iterator进行实现的

为了验证foreach循环是使用Iterator作为内部实现这一事实,我们依然采用本文最开始的实例进行验证:

1 public classItaratorTest {2

3 public static voidmain(String[] args) {4 Collection list = new ArrayList();5 list.add("Android");6 list.add("IOS");7 list.add("Windows Mobile");8

9 //example110 //Iterator iterator = list.iterator();11 //while (iterator.hasNext()) {12 //String lang = iterator.next();13 //list.remove(lang);14 //}15

16 //example 2

17 for(String language : list) {18 list.remove(language);19 }20 }21

22 }

程序运行时所报异常:

Exception in thread "main"java.util.ConcurrentModificationException

at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)

at java.util.ArrayList$Itr.next(ArrayList.java:831)

at Text.ItaratorTest.main(ItaratorTest.java:22)

此异常正说明了for-each循环内部使用了Iterator来遍历Collection,它也调用了Iterator.next(),这会检查(元素的)变化并抛出ConcurrentModificationException。

总结:

在遍历collection时,如果要在遍历期间修改collection,则必须通过Iterator/listIterator来实现,否则可能会发生“不确定的后果”。

foreach循环通过iterator实现,使用foreach循环的对象必须实现Iterable接口

java for循环迭代_JAVA中的for-each循环与迭代相关推荐

  1. java中的循环语句_Java中三种常用的循环语句,一看就懂~

    循环语句:满足一定条件的情况下反复执行一个操作. Java中提供三种常用的循环语句: 1.while循环语句 while先判断为真,再执行while循环语句,如果条件为假,则跳出循环 语法如下: Wh ...

  2. java数组最大值索引_java中的权限修饰符有哪些?怎么获取数组最大值?

    java作为一门编程语言,由于它的优秀,现在已经成为很多人的首选编程语言.java中关于修饰符和数组的知识点也是十分多的,今天就来为大家介绍一下,java中的权限修饰符有哪些?怎么获取数组最大值?一起 ...

  3. java递归和迭代_Java中的迭代与递归

    递归 提到迭代,不得不提一个数学表达式: n!=n*(n-1)*(n-2)*...*1 有很多方法来计算阶乘.有肯定数学基础的人都知道n!=n*(n-1)!因而,代码的实现可以直接写成: 代码一 in ...

  4. java 删除list元素_JAVA中循环删除list中元素的方法总结

    印象中循环删除list中的元素使用for循环的方式是有问题的,但是可以使用增强的for循环,然后今天在使用时发现报错了,然后去科普了一下,再然后发现这是一个误区.下面就来讲一讲..伸手党可直接跳至文末 ...

  5. java 遍历对象_java中some(),every()循环遍历,Object.getOwnPropertyNames()遍历对象的属性...

    由于java知识的应用具有一定的广泛性,所以它经常会应用到我们的日常使用当中.那么今天就为大家介绍一下java中some(),every()循环遍历,Object.getOwnPropertyName ...

  6. java list 范围删除_JAVA中循环删除list中元素(移除list两时间范围外的元素)

    印象中循环删除list中的元素使用for循环的方式是有问题的,但是可以使用增强的for循环,然后今天在使用时发现报错了,然后去科普了一下,再然后发现这是一个误区.下面就来讲一讲..伸手党可直接跳至文末 ...

  7. java的循环控制结构有哪些_java中的控制结构(if,循环)详解

    1 说明JAVA语言中三种控制循环结构的代码形式(其他 1. while(condition){ statements; } 其中,condition是任何布尔表达式,其返回值为true 或 fals ...

  8. java循环遍历_JAVA中循环遍历list有三种方式

    转自:https://blog.csdn.net/changjizhi1212/article/details/81036509 JAVA中循环遍历list有三种方式for循环.增强for循环(也就是 ...

  9. java switch语句套循环_java中switch语句和循环语句的使用

    java中switch语句和循环语句的使用 发布时间:2020-06-17 10:49:18 来源:亿速云 阅读:121 作者:Leah 这篇文章运用简单易懂的例子给大家介绍java中switch语句 ...

最新文章

  1. 在一家开源公司工作的体验!
  2. LeetCode算法题-Reverse Linked List(Java实现)
  3. PCB 围绕CAM自动化,打造PCB规则引擎
  4. python自动发邮件富文本_django 实现后台从富文本提取纯文本
  5. c语言斐波那契数列_视频丨神奇的斐波那契数列科学性与艺术性
  6. 计算机视觉 | Python OpenCV 3 使用背景减除进行目标检测
  7. Oracle BBED 工具介绍
  8. 在linux中配置安装telnet服务
  9. Python机器学习:SVM005SVM使用多项式特征
  10. 怎么看tomcat连接的哪个mysql_如何验证tomcat和mysql连接成功呢
  11. matlab2c使用c++实现matlab函数系列教程-cos函数
  12. 小学四年级计算机教案清华出版,清华版四年级下册信息技术电子备课教案
  13. 哈希值 是什么?哈希值是什么东西啊?具体怎么识别?怎么用?
  14. 图片默认底部3px缝隙
  15. android百度地图路线查询,Android百度地图——路线规划搜索
  16. 利用php的GD库封装的海报demo
  17. 淘宝装修前需要了解的css小技巧
  18. HyperLynx(二十三)DDR(六)DDRx总线批量仿真
  19. 串口调试助手总是多发送两个字节 0d 0a
  20. TIA博图——基本操作

热门文章

  1. 她是直播聊学习成“网红”的北大博士,毕业后入职民办学校,年薪70万
  2. 脑洞大开!Adobe等新研究把「自拍」变「他拍」,魔幻修图效果感人
  3. 知识蒸馏在推荐系统的应用
  4. 6G+128G的华为新机真香,自费送一台!
  5. 热榜第一!GitHub 标星 5.6w,如何用 Python 实现所有算法?
  6. 作为CTO,我为什么必须要求代码进行Code Review!
  7. 北大女学霸看什么技术书?包邮送30本同款!
  8. Python匿名函数:lamdba()函数
  9. 深度学习100问:图像语义分割有哪些经典的上采样方法?
  10. 链表问题7——判断一个链表是否为回文结构