for-each解惑

从Java5起,在Java中有了for-each循环,能够用来循环遍历collection和array。For each循环容许你在无需保持传统for循环中的索引,或在使用iterator /ListIterator时无需调用while循环中的hasNext()方法就能遍历collection。Java中,for-each循环简化了任何Collection或array的遍历过程,但并非每一个Java程序员都了解本文将要描述的for-each 循环的一些细节。与 Java5 发布的其余术语:释放别名泛型,自动封装和可变参数不一样,Java开发者对for-each循环的使用比任何其余特性更加频繁,但当问及高级的for-each循环怎样工做,或什么是在for-each循环中使用Collection时的基本需求时,就不是每一个人都可以回答的了。本篇教程和例子旨在经过深刻研究for-each 循环中几个有趣的难题来填补上述空白(说明上述问题)。好了,再也不赘述,一块儿看看咱们在Java5 for-each循环的第一个问题。html

高级循环问题 1

考虑下面这段遍历一个用户自定义的aggregator或collection类的代码,这段代码将会打印出什么,抛出异常仍是编译器错误:java

1程序员

2express

3app

4oop

5ui

6this

7spa

8.net

9

10

11

12

13

14

15

16

17

18

19

package test;

 

/**

  * Java Class to show how for-each loop works in Java

  */

public class ForEachTest { 

 

    public static void main(String args[]){

        CustomCollection<String> myCollection = new CustomCollection<String>();

        myCollection.add("Java");

        myCollection.add("Scala");

        myCollection.add("Groovy");

 

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

        for(String language: myCollection){

            System.out.println(language);

        }

    }

}

下面是咱们的CustomCollection类,这是个参数为泛型的类,与任何其余的Collection类类似,依靠于ArrayList并提供从Collection中添加和删除项的方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

package test;

 

public class CustomCollection<T>{

    private ArrayList<T> bucket;

 

    public CustomCollection(){

        bucket = new ArrayList();

    }

 

    public int size() {

        return bucket.size();

    }

 

    public boolean isEmpty() {

        return bucket.isEmpty();

    }

 

    public boolean contains(T o) {

        return bucket.contains(o);

    }

 

    public boolean add(T e) {

        return bucket.add(e);

    }

 

    public boolean remove(T o) {

        return bucket.remove(o);

    }  

 

}

答案:

上述代码将没法经过编译,这是由于咱们的CustomCollection类没有实现java.lang.Iterable接口,编译期错误以下:

1

2

3

4

5

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - for-each not applicable to expression type

 

 required: array or java.lang.Iterable

  found:    test.CustomCollection

        at test.ForEachTest.main(ForEachTest.java:24)

从中了解到的一个有趣的事实是:for-each循环仅应用于实现了Iterable接口的Java array和Collection类,并且既然全部内置Collection类都实现了java.util.Collection接口,已经继承了Iterable,这一细节一般会被忽略,这点能够在Collection接口的类型声明“ public interface Collection extends Iterable”中看到。因此为了解决上述问题,你能够选择简单地让CustomCollection实现Collection接口或者继承AbstractCollection,这是默认的通用实现并展现了如何同时使用抽象类和接口以获取更好的灵活性。如今让咱们来看看for-each循环的第二个难题:

Java for-each循环的第二个难题:

在下面的代码示例将会抛出ConcurrentModificationException异常。这里咱们使用标准iterator和for-each循环遍历ArrayList,随后删除元素,你须要找出哪段代码将会抛出ConcurrentModificationException ,为何?请注意,答案多是两个都会,都不会或其中之一。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

package test;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.Iterator;

 

/**

  * Java class to demonstrate inner working of for-each loop in Java

  * @author Javin Paul

  **/

public class ForEachTest2 { 

 

    public static void main(String args[]){

        Collection<String> list = new ArrayList<String>();

        list.add("Android");

        list.add("iPhone");

        list.add("Windows Mobile");

 

        // Which Code will throw ConcurrentModificationException, both,

       // none or one of them

 

        // example 1       

        Iterator<String> itr = list.iterator();

        while(itr.hasNext()){

            String lang = itr.next();

            list.remove(lang);

        }

 

         // example 2

        for(String language: list){

            list.remove(language);

        }

    }

}

大约70%的Java开发者都会说第一个代码块会抛出ConcurrentModificationException异常,由于咱们没有用iterator的remove方法来删除元素,而是使用ArrayList的 remove()方法。可是,没有多少Java开发者会说出for-each循环也会出现一样的问题,由于咱们在这里没有使用iterator。事实上,第二个代码片断也会抛出ConcurrentModificationException异常,这点在解决了第一个困惑以后就变得很明显了。既然for-each循环内部使用了Iterator来遍历Collection,它也调用了Iterator.next(),这会检查(元素的)变化并抛出ConcurrentModificationException。你能够从下面的输出中了解到这点,在注释掉第一个代码段后,当你运行第二个代码段时会获得下面的输出。

1

2

3

4

Exception in thread "main" java.util.ConcurrentModificationException

        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)

        at java.util.AbstractList$Itr.next(AbstractList.java:343)

        at test.ForEachTest2.main(ForEachTest2.java:34)

以上就是关于Java5 for-each循环的所有内容。咱们已经看到了Java程序员在编写遍历Collection类的代码时产生的不少问题,特别是在遍历collection的同时删除元素的时候。请牢记,在从任何Collection(例如Map、Set或List)中删除对象时总要使用Iterator的remove方法,也请谨记for-each循环只是标准Iterator代码标准用法之上的一种语法糖(syntactic sugar)而已。

译者注:语法糖(syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达-Peter J. Landin发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并无影响,可是更方便程序员使用。一般来讲使用语法糖可以增长程序的可读性,从而减小程序代码出错的机会。

原文连接: javarevisited 翻译: ImportNew.com liqing
译文连接: http://www.importnew.com/11038.html

相关文章
相关标签/搜索