JAVA/Effective Java

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

꾸준함. 2024. 3. 16. 03:51

아이템 45에서 다루었다시피 stream이 제격인 작업이 있고 반복이 제격인 작업이 있습니다.

 

 

 

앞서 아이템 57에서도 언급했듯이 for문과 같은 광용구들은 while문보다는 낫지만 다음 이유 때문에 최선의 방법은 아닙니다.

  • 진짜 필요한 것은 원소들 뿐이지만 위 코드처럼 작성할 경우 반복자와 인덱스 변수 모두 선언해야 하기 때문에 코드가 지저분해짐
  • 컬렉션이나 배열이여냐에 따라 코드 형태가 달라짐

 

for-each문

  • 정식 이름은 `향상된 for문(enhanced for statement)`
  • for-each 문은 컬렉션과 배열은 물론 Iterable 인터페이스를 구현한 객체라면 무엇이든 순회 가능
  • 반복자와 인덱스 변수를 사용하지 않기 때문에 코드가 깔끔해지고 오류가 날 일이 없음
  • 하나의 관용구로 되어있어 컬렉션과 배열 모두 같은 코드 형태이며 성능도 동일
  • 콜론(:)은 안의(in) 라고 읽으면 됨
    • 따라서 아래 코드의 반복문은 `elements 안의 각 원소 e에 대해`라고 해석하면 됨

 

 

1. 중첩 컬렉션에서 for-each문의 이점 극대화


 

코드 부연 설명

  • 위 코드에서 Iterator를 사용할 경우 `deck.add(new Card(i.next(), j.next()));`에서 NoSuchElementException 예외 발생
    • next()가 Suit 하나당 한 번식만 불려야 하는데
    • 안쪽 반복문에서 호출되는 바람에 Rank 하나당 한 번씩 불렸기 때문
    • 위 코드를 고친다고 해도 코드가 지저분해지는 단점 존재


  • 반면 for-each문을 사용하면 깔끔하고 간단하게 오류를 유발하지 않는 코드를 작성할 수 있음

 

 

2. for-each문을 사용할 수 없는 케이스

 

2.1 파괴적인 필터링(destructive filtering)

  • 리스트를 순회하면서 원소를 제거할 때, 리스트의 구조가 변경되면서 ConcurrentModificationException이 발생
  • 컬렉션을 순회하면서 선택된 원소를 제거해야 할 경우 반복자의 remove 메서드를 호출해야 함
  • 자바 8버전부터 Collection의 removeIf 메서드를 사용해 컬렉션을 명시적으로 순회하지 않아도 됨

 

 

 

2.2 변형(transforming)

  • 리스트나 배열을 순회하면서 원소 값 일부 혹은 전체를 교체하는 경우에는 인덱스를 사용해야 함
  • ex) arr[i] = 1;

 

2.3 병렬 반복(parallel iteration)

  • 여러 컬렉션을 병렬로 순회해야 할 경우 각각의 반복자와 인덱스 변수를 사용해 엄격하고 명시적으로 제어해야 함
  • for-each문은 각각의 요소에 대해 반복할 때마다 내부적으로 반복자(iterator)를 사용하여 요소를 가져오는데, 이러한 반복자는 병렬 처리를 지원하지 않음

 

참고

이펙티브 자바

 

반응형