58. 전통적인 for 문보다는 for-each 문을 사용하라
✅ 핵심 요약
for-each 문(향상된 for 문)을 사용하면 코드가 간결해지고, 오류 발생 가능성을 줄일 수 있으며, 가독성이 향상됩니다. 전통적인 for문 (인덱스 사용)이나 Iterator를 직접 사용하는 방식보다 훨씬 안전하고 명확하므로, 가능한 모든 경우에 for-each 문을 사용하는 것이 좋습니다.
📚 필수 개념 및 배경 지식
이 아이템을 제대로 이해하려면 다음 개념들을 알아두는 것이 좋습니다.
전통적인 for 문
• for (int i = 0; i < list.size(); i++) { list.get(i) }
• 인덱스로 접근 가능한 자료구조에만 사용 가능
• 인덱스 조작이 필요할 때 유용하지만 실수 위험 높음
Iterator 방식
• Iterator<T> it = list.iterator();
• while (it.hasNext()) { T item = it.next(); }
• 모든 컬렉션에 사용 가능하고 요소 삭제(remove())도 가능
• 코드가 길고 복잡함
for-each 문
• for (String item : items) { ... }
• Java 5부터 도입된 간결한 문법
• 가독성 높고 실수 가능성 낮음
• 인덱스 접근이나 수정은 불가능
Iterable
• for-each를 사용하기 위한 필수 인터페이스
• iterator() 메서드 하나만 구현하면 됨
• 모든 Java 컬렉션은 기본적으로 구현되어 있음
✅ 올바른 예제 (for-each 사용)
import java.util.*;
// 카드 무늬 (Suit): 총 4가지
enum Suit {
CLUB, DIAMOND, HEART, SPADE
}
// 카드 숫자 (Rank): 총 13가지
enum Rank {
ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN, JACK, QUEEN, KING
}
// 카드 클래스
class Card {
private final Suit suit;
private final Rank rank;
public Card(Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
@Override
public String toString() {
return rank + " of " + suit;
}
}
public class DeckForEachExample {
public static void main(String[] args) {
// 무늬와 숫자 리스트 생성
Collection<Suit> suits = Arrays.asList(Suit.values()); // 4개
Collection<Rank> ranks = Arrays.asList(Rank.values()); // 13개
List<Card> deck = new ArrayList<>();
// ✅ for-each 문으로 4 × 13 = 52장 카드를 안전하게 생성
for (Suit suit : suits) {
for (Rank rank : ranks) {
deck.add(new Card(suit, rank));
}
}
System.out.println("총 카드 수: " + deck.size()); // ✅ 출력: 52
System.out.println("생성된 카드 예시:");
for (int i = 0; i < 5; i++) {
System.out.println(deck.get(i));
}
}
}❌ 잘못된 예제 (버그 발생)
🔎 문제: 바깥 반복자인 i.next()가 안쪽 반복문에서 계속 실행되면서, 바깥 컬렉션이 빨리 끝나버림 → 예외 발생 또는 누락
🛠 특별한 상황에서는 전통적인 for 문이 더 적절
📦 자바 버전에 따른 변화
☕ Java 8 이후
Collection.removeIf() 메서드 추가: 컬렉션에서 필터링하며 원소를 제거할 때 for 문 대신 사용 가능
스트림 API: stream().filter().collect() 같은 방식으로 필터링 및 변환 가능
💡 핵심 포인트
✨ for-each를 써야 하는 이유
가독성 및 간결성:
for-each는 반복자나 인덱스 변수 선언 및 관리 코드가 없어 훨씬 깔끔합니다.for-each문은 배열과 컬렉션 모두에 사용할 수 있다성능은 전통적인 반복문과 차이가 없다
🚫 for-each를 쓸 수 없는 경우
예외 상황: 다음의 경우에는
for-each를 사용할 수 없음파괴적인 필터링 : 원소를 삭제하면서 순회할 때 (→
Iterator.remove()필요)변형 : 원소를 수정할 때 (인덱스 필요)
병렬 반복 : 두 개 이상의 리스트를 동시에 순회할 때
✅ 결론
단순 순회에는 무조건
for-each를 사용하세요. 코드가 더 안전하고 읽기 쉬워집니다.for-each를 사용할 수 없는 명확한 예외 상황(제거, 수정, 병렬 반복)에서만 다른 방법을 고려하고, 이때는 관련 버그에 주의해야 합니다.
🎯 느낀점
처음엔
for-each문이 단순히 짧은 문법이라 생각했는데, 이 아이템을 공부하면서 실수를 줄이고 코드 품질을 높이는 핵심 도구라는 걸 느꼈어요.특히 중첩 반복문에서
next()를 잘못 쓰면 큰 버그가 생긴다는 걸 보면서, for-each는 단순히 "간편함"을 넘어서 안정성과 신뢰성을 주는 문법이라고 이해하게 되었습니다.이제 반복문을 작성할 땐, "이 작업이 for-each로 가능한가?" 먼저 떠올리게 되었습니다.
Last updated