对于遍历数组或者集合的元素来说,一般我们都会想到用传统的for循环,要么使用数组下标进行索引,要么使用集合的迭代器进行遍历,迭代器和索引变量在每个循环中出现三次,其中有两次是非常容易出现错误的,一旦出现错误,有可能编译器不能发现错误。

在java1.5中发行版本中引入的for-each循环,其中隐藏了迭代器或者索引变量,避免混乱和出错的可能。

看看下面的例子就很容出现错误:

//花色
public enum Suit {
    CLUB,DIAMOND,HEART,SPARE
}
//大小
public enum Rank {
    ACE,DEUCE,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN,JACK,QUEEN,KING
}

public class Card {

    static Collection<Suit> suit=Arrays.asList(Suit.values());
    static Collection<Rank> rank=Arrays.asList(Rank.values());

    public static void main(String[] args) {
        for(Iterator<Suit> i=suit.iterator();i.hasNext();){
            for(Iterator<Rank> j=rank.iterator();j.hasNext();){
                System.out.println(i.next()+"+"+j.next());
            }
        }

    }

}

结果:

CLUB+ACE 
 DIAMOND+DEUCE 
 HEART+THREE 
 SPARE+FOUR 
 Exception in thread “main” java.util.NoSuchElementException 
 at java.util.AbstractList$Itr.next(AbstractList.java:364) 
 at com.num46.Card.main(Card.java:15)

注意此程序的陷阱,此程序想打印出一副没有大小王的牌,用迭代器进行遍历。但是打印出来是错误的结果,是因为程序在里面进行了遍历,两个循环进行每一次遍历之后,内外层都会进行遍历。
当外层的循环比内层的循环的次数更小时,会抛出NoSuchElementException的异常

程序的改进:
方法一:在外层循环的作用域中,添加一个变量保存外层元素

public static void main(String[] args) {
        for(Iterator<Suit> i=suit.iterator();i.hasNext();){
            Suit suitValue=i.next();
            for(Iterator<Rank> j=rank.iterator();j.hasNext();){
                System.out.println(suitValue+"+"+j.next());
            }
        }
    }

这样便能打印出正常的结果,但是这种方法还是会出现迭代器或者数组的索引变量,容易造成混乱。这时候就应该用到for-each循环

方法二:使用for-each循环

static void foreachMethod(){
        for (Suit suit2 : suit) {
            for (Rank rank2 : rank) {
                System.out.println(suit2+"+"+rank2);
            }
        }
    }

从上面的例子可以看出,使用for-each循环以后,程序清晰了很多,并且不容易出错。

再看看类似的陷阱

public enum Face {
    ONE,TWO,THREE,FOUR,FIVE,SIX
}

public class Dot {
    static Collection<Face> dot1=Arrays.asList(Face.values());
    static Collection<Face> dot2=Arrays.asList(Face.values());

    public static void main(String[] args) {
        for (Iterator<Face> i=dot1.iterator(); i.hasNext(); ) {
            for (Iterator<Face> j = dot2.iterator(); j.hasNext(); ) {
                System.out.println(i.next()+" + "+j.next());
            }
        }

    }

}

上面的例子是同时投掷两个骰子,打印出所有的情况,但是打印的结果是6种结果,而不是36种结果

结果:
ONE + ONE
TWO + TWO
THREE + THREE
FOUR + FOUR
FIVE + FIVE
SIX + SIX

解决的方法是用上面的两种解决方法,但是用for-each循环比较好

for-each循环能遍历所有实现了Iterable接口的对象!!!!

总之,for-each循环在简洁性和预防Bug方面是传统for循环是做不到的,并且其对于for循环来说还没有性能损失,在某些情况下还可能比传统的for循环还稍微有些性能优势,故要尽量使用for-each循环。