기록이 힘이다.

[이펙티브 자바] 58. 전통적인 for문보다는 for-each문을 사용하라 본문

JAVA

[이펙티브 자바] 58. 전통적인 for문보다는 for-each문을 사용하라

dev22 2023. 4. 20. 07:01
728x90

컬렉션 순회하기

for(Iterator<Element> i = c.iterator(); i.hasNext();){
	Element e = i.next();
  ... //e로 무언가를 한다.
}

배열 순회하기

for(int i =0; i<a.length; i++){
		... //a[i]로 무언가를 한다.
}

while 문보다는 낫지만 가장 좋은 방법은 아니다. 진짜 필요한 건 원소들 뿐이다.

변수를 잘못 사용할 틈새가 넓어진다. 컬렉션이냐 배열이냐에 따라 코드 형태가 상당히 달라진다.

이상의 문제는 for-each문을 사용하면 모두 해결된다. for-each문의 정식 이름은 향상된 for 문(enhanced for statement)’ 다.

반복자와 인덱스 변수를 사용하지 않으니 코드가 깔끔해지고 오류가 날 일도 없다.

컬렉션과 배열을 순회하는 올바른 관용구

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

반복 대상이 컬렉션이든 배열이든, for-each문을 사용해도 속도는 그대로다.

package effectivejava.chapter9.item58;

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()));

        // 코드 58-7 컬렉션이나 배열의 중첩 반복을 위한 권장 관용구 (349쪽)
        for (Suit suit : suits)
           for (Rank rank : ranks)
               deck.add(new Card(suit, rank));
    }
}
package effectivejava.chapter9.item58;
import java.util.*;

// 코드 58-5 같은 버그, 다른 증상! (349쪽)
public class DiceRolls {
    enum Face { ONE, TWO, THREE, FOUR, FIVE, SIX }

    public static void main(String[] args) {
        // 같은 버그, 다른 증상!
        Collection<Face> faces = EnumSet.allOf(Face.class);

        for (Iterator<Face> i = faces.iterator(); i.hasNext(); )
            for (Iterator<Face> j = faces.iterator(); j.hasNext(); )
                System.out.println(i.next() + " " + j.next());

        System.out.println("***************************");

        // 컬렉션이나 배열의 중첩 반복을 위한 권장 관용구
        for (Face f1 : faces)
            for (Face f2 : faces)
                System.out.println(f1 + " " + f2);
    }
}

for-each 문을 사용할 수 없는 상황 세 가지 존재

  1. 파괴적인 필터링 - 컬렉션을 순회 선택 원소 제거 시 반복자의 remove 메서드 호출/ 자바 8 부터는 Collection의 removeIf 메서드 사용 컬렉션 명시적 순회
  2. 변형 - 리스트나 배열 순회 그 원소의 값 일부 혹은 전체 교채 리스트의 반복자나 배열의 인덱스를 사용
  3. 병렬반복 - 각각의 반복자와 인덱스 변수 사용 엄격 명시 제어

for-each 문은 컬렉션과 배열은 물론 Iterable 인터페이스를 구현한 객체라면 무엇이든 순회할 수 있다.

public interface Iterable<E>{
	//이 객체의 원소들을 순회하는 반복자를 반환한다.
  Iterator<E> iterator();
}