星空网 > 软件开发 > Java

JAVA中的for

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

一、迭代器Iterator

接口:Iterator<T>

1 public interface Iterator<E>{2 3  boolean hasNext();4 5  E next();6 7 void remove();8 }

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

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

 1 import java.util.ArrayList; 2 import java.util.Collection; 3 import java.util.Iterator; 4  5 public class ItaratorTest { 6  7   public static void main(String[] args) { 8     Collection<String> list = new ArrayList<String>(); 9     list.add("Android");10     list.add("IOS");11     list.add("Windows Mobile");12 13     Iterator<String> 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<T>

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

  1. 使用foreach循环的对象,必须实现了Iterable<T>接口

请看如下示例:

 1 import java.util.ArrayList; 2  3 public class ForeachTest1 { 4  5   public static void main(String args[]) { 6     CustomCollection<String> myCollection = new CustomCollection<String>(); 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 error13     for (String language : myCollection) {14       System.out.println(language);15     }16   }17 18   private class CustomCollection<T> {19     private ArrayList<T> bucket;20 21     public CustomCollection() {22       bucket = new ArrayList();23     }24 25     public int size() {26       return bucket.size();27     }28 29     public boolean isEmpty() {30       return bucket.isEmpty();31     }32 33     public boolean contains(T o) {34       return bucket.contains(o);35     }36 37     public boolean add(T e) {38       return bucket.add(e);39     }40 41     public boolean remove(T o) {42       return bucket.remove(o);43     }44 45   }46 }

 

 

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

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<T>接口的对象。由于所有内置Collection类都实现了java.util.Collection接口,已经继承了Iterable,所以为了解决上述问题,可以选择简单地让CustomCollection实现Collection接口或者继承AbstractCollection。解决方式如下:

 1 import java.util.AbstractCollection; 2 import java.util.ArrayList; 3 import java.util.Iterator; 4  5 public class ForeachTest { 6   public static void main(String args[]) { 7     CustomCollection<String> myCollection = new CustomCollection<String>(); 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<T> extends AbstractCollection<T> {17     private ArrayList<T> bucket;18 19     public CustomCollection() {20       bucket = new ArrayList();21     }22 23     public int size() {24       return bucket.size();25     }26 27     public boolean isEmpty() {28       return bucket.isEmpty();29     }30 31     public boolean contains(Object o) {32       return bucket.contains(o);33     }34 35     public boolean add(T e) {36       return bucket.add(e);37     }38 39     public boolean remove(Object o) {40       return bucket.remove(o);41     }42 43     @Override44     public Iterator<T> iterator() {45       // TODO Auto-generated method stub46       return bucket.iterator();47     }48   }49 }

 

 

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

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

 1 public class ItaratorTest { 2  3   public static void main(String[] args) { 4     Collection<String> list = new ArrayList<String>(); 5     list.add("Android"); 6     list.add("IOS"); 7     list.add("Windows Mobile"); 8  9     // example110     // Iterator<String> iterator = list.iterator();11     // while (iterator.hasNext()) {12     // String lang = iterator.next();13     // list.remove(lang);14     // }15 16     // example 217     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

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

亚马逊FBA退款金额最多的4种场景,怎么把这些美金拿到自己账户?:https://www.ikjzd.com/articles/142160
跨境卖家春节期间如何备货:https://www.ikjzd.com/articles/142161
2021年需要关注的11个电商趋势:https://www.ikjzd.com/articles/142162
2021海外网红营销避坑指南:https://www.ikjzd.com/articles/142164
京东物流正式向港交所递交IPO招股书,成京东旗下第三家进行IPO子公司:https://www.ikjzd.com/articles/142166
什么是PSE认证?亚马逊日本站METI备案如何选择?:https://www.ikjzd.com/articles/142169
无锡旅游景点竹海 - 无锡的竹海:https://www.vstour.cn/a/363178.html
5月贾汪好玩的地方 贾汪哪有好玩的地方:https://www.vstour.cn/a/363179.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流