java for循环迭代_JAVA中的for-each循环与迭代

在学习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接口

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值