도당탕탕
Item58 : 전통적인 FOR LOOP 보다 FOR EACH LOOP를 선호하라. 본문
for (Element e : elements) {
...// Do something with e
}
- 위는
for each element e in elements
라고 읽힌다. - foreach 문은 전통적인 for loop와 비교했을 때 성능차이가 없다.
FOR EACH의 장점
// Can you spot the bug?
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());
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()));
위 코드에는 버그가 있다. 바로 바깥 for문에 있는 Iterator i가 너무 많이 호출된다는 점이다. 결국 NoSuchElementException
이 발생할 가능성이 있고, exception이 나지 않더라도 비정상적인 결과가 나타나게 된다.
다음처럼 Suit 값을 저장해서 해결할 수 있다.
// Fixed, but ugly - you can do better!
for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ) {
Suit suit = i.next();
for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
deck.add(new Card(suit, j.next()));
}
하지만 중첩 for-each문을 사용해서 더 간결하게 문제를 해결할 수 있다.
for (Suit suit : suits)
for (Rank rank : ranks)
deck.add(new Card(suit, rank));
for-each를 쓸 수 없는 경우
- 파괴적 필터링 - Collection을 순회하면서
remove
함수를 호출해야 하는 경우 - 변환 - 리스트 또는 배열을 순회하면서 일부 값들을 치환해야 하는 경우, 인덱스나 iterator를 사용할 수밖에 없다.
- 병렬 순회 - 여러 컬레션들을 병렬로 순회해야 할 경우
Iterable interface를 구현하는 객체들은 모두 for-each 문으로 순회가능하다.
public interface Iterable<E> {
// Returns an iterator over the elements in this iterable Iterator<E> iterator();
}
정리
for-each loop는 명료성, 유연함, 버그 방지, no performance penalty(성능저하 없음) 측면에서 확실한 장점이 있으므로, 가능하면 for loop 대신에 for-each 문을 사용하라.
'JAVA' 카테고리의 다른 글
Item60 : 정확한 답이 요구되지 않으면, FLOAT와 DOUBLE을 피하라. (0) | 2023.01.13 |
---|---|
Item59 : 라이브러리를 익히고 사용하라 (0) | 2023.01.13 |
Item57 : 지역변수의 범위를 최소화하라 (2) | 2023.01.12 |
Item56 : 공개된 API에는 항상 문서화 주석을 작성하라 (0) | 2023.01.11 |
Item55: 옵셔널 반환은 신중히 하라 (0) | 2023.01.11 |
Comments