전통적인 for

for (Iterator<Element> i = c.iterator(); i.hasNext()) {
  Element e = i.next();
  // do something with e...
}

for (int i = 0; i < a.length; i++) {
  // do something with e...
}

[아이템 57] 에서 보았듯이, 위의 관용구들은 while 문보다는 낫지만 가장 좋은 방법은 아니다.

⭐ 전통적인 for문의 문제점

1. 반복자와 인덱스 변수는 모두 코드를 지저분하게 할 뿐, 우리에게 진짜 필요한 건 **원소**들뿐이다.
2. 사용되는 요소 종류가 늘어나면 오류 가능성이 높아진다.
3. 잘못된 변수를 사용했을 때 컴파일러가 잡아준다는 보장이 없다.
4. 컬렉션이냐 배열이냐에 따라 코드 형태가 많이 다르다.

for-each

위의 문제들은 모두 for-each(enhanced for statement) 문을 사용하면 해결된다.

⭐ for-each문의 장점

1. 반복자와 인덱스 변수를 사용하지 않아 코드가 깔끔하고 오류가 나지 않는다.
2. 하나의 관용구로 컬렉션과 배열을 모두 처리할 수 있다.

Untitled

for (Element e : elements) {
	... // e로 무언가를 한다.
}

컬렉션을 중첩하여 순회해야 한다면 for-each 문의 이점이 더욱 커진다.

다음 코드에서 버그를 찾아보자! 반복문을 중첩할 때 흔히 저지르는 실수가 담겨있다.

import java.util.*;

public class Card {
    private final Suit suit;
    private final Rank rank;

    enum Suit { CLUB, DIAMOND, HEART, SPADE }
    enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
        NINE, TEN, JACK, QUEEN, KING }

    static Collection<Suit> suits = Arrays.asList(Suit.values());
    static Collection<Rank> ranks = Arrays.asList(Rank.values());

    Card(Suit suit, Rank rank ) {
        this.suit = suit;
        this.rank = rank;
    }

    public static void main(String[] args) {
        List<Card> deck = new ArrayList<>();
        
        for (Iterator<Suit> i = suits.iterator(); i.hasNext(); )
            for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
                deck.add(new Card(i.next(), j.next()));
		}
}

위의 코드의 문제점은 suits 의 반복자에서 next 메서드가 너무 많이 호출된다는 것이다.

next 메서드는 ‘숫자(Suit) 하나당’ 한 번씩만 불려야 하는데, 안쪽 반복문에서 호출되는 바람에 ‘카드(Rank) 하나당’ 한 번씩 호출되고 있다.