아이템 58. 전통적인 for문 보다는 for-each 문을 사용하라

wisdom·2022년 10월 14일
0

Effetctive Java

목록 보기
58/80
post-thumbnail

전통적인 for 문의 문제점

전통적인 for 문은 while 문보다는 낫지만 가장 좋은 방법은 아니다.

  1. 반복자와 인덱스 변수는 코드를 지저분하게 한다.
  2. 사용되는 요소의 종류가 늘어나 오류 가능성이 높아진다.
  3. 컬렉션과 배열의 코드 형태가 상당히 달라진다.
  4. 컬렉션의 중첩 반복 시, 일반적인 반복문을 사용하면 실수하기 쉽다.
// 컬렉션 순회
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
	Element e = i.next();
    ...
}

// 배열 순회
for (int i = 0; i < a.length; i++) {
    ... 
}

// 컬렉션 중첩 순회 - 실수하기 쉽고, 보기 좋지 않다.
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 문 (enhanced for statement)

// 컬렉션 혹은 배열 순회
for (Element e : elements) {
	...
}

// 컬렉션이나 배열의 중첩 순회
for (Suit suit : suits)
    for (Rank rank : ranks)
        deck.add(new Card(suit, rank));

위에서 언급한 문제들은 for-each 문을 사용하면 모두 해결된다.

  • 반복자와 인덱스 변수를 사용하지 않아 코드가 깔끔해지고 오류가 날 일이 없다. (1,2번)
  • 하나의 관용구로 컬렉션과 배열을 모두 처리할 수 있어 어떤 컨테이너를 다루는지 신경쓰지 않아도 된다. (3번)
  • 컬렉션과 배열 뿐만 아니라, Iterable 인터페이스를 구현한 객체는 모두 순회 가능하다.
  • 반복 대상이 컬렉션이든 배열이든 속도적인 측면에서 전통적인 for 문과 차이가 없다.
    for-each 문이 만들어내는 코드는 사람이 손으로 최적화한 것과 사실상 같기 때문이다.
  • 컬렉션 중첩 순회 시, 코드가 간결해지며 실수로 인한 버그를 예방해준다.

for-each 문을 사용할 수 없는 경우

1. 파괴적인 필터링 (destructive filtering)

컬렉션을 순회하면서 선택된 원소를 제거해야 한다면, 반복자의 remove 메서드를 호출해야 한다.

자바 8부터는 Collection의 removeIf 메서드를 사용해 컬렉션을 명시적으로 순회하는 일을 피할 수 있다.

2. 변형 (transforming)

리스트나 배열을 순회하면서 그 원소의 값 일부 혹은 전체를 교체해야 한다면, 리스트의 반복자나 배열의 인덱스를 사용해야 한다.

3. 병렬 반복 (parallel iteration)

여러 컬렉션을 병렬로 순회해야 한다면, 각각의 반복자와 인덱스 변수를 사용해 엄격하고 명시적으로 제어해야 한다.


📌 핵심 정리

  • 전통적인 for 문과 비교했을 때 for-each 문은 명료하고, 유연하고, 버그를 예방해준다.
  • 성능 저하도 없다.
  • 가능한 모든 곳에서 for 문이 아닌 for-each 문을 사용하자.
profile
백엔드 개발자

0개의 댓글