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

박상준·2024년 7월 6일
0

이펙티브 자바

목록 보기
18/19

전통적인 for 문의 문제점

일반 컬렉션 순회

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

배열 인덱스 순회

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

문제점

  • 반복자, 인덱스 변수로 인해 코드의 복잡성이 증가된다.
  • 오류 가능성이 증가함
    • 반복자는 3번, 인덱스는 4번 등장하는 등..
  • 배열은 인덱스 순회, 컬렉션은 반복자 순회로
    • 각 자료 타입마다 순회 방식이 달라는 문제

for-each 문 ( 향상된 for 문)

for (Element e : elements) {
    ... // e로 무언가를 한다.
}
  • 장점
    • 코드가 간결
    • 오류 가능성 감소
    • 컬렉션이나 배열모두에 적용이 가능함.
  • 성능면에서
    • for-each 문과 전통적인 for 문의 성능 차이는 없다.

    • 컴파일러가 더 최적화된 코드를 생성한다는 점이 다름.

      어떻게 최적화 된 코드를 뽑아내는 것인가?

      1. 배열에 대한 최적화

        // 원본 for-each 문
        for (int value : array) {
            // value 사용
        }
        ---
        // 최적화 전 (전통적인 for 문)
        for (int i = 0; i < myArray.length; i++) {
            int value = myArray[i];
            // value 사용
        }
        ---
        // 컴파일러가 생성하는 최적화된 코드
        int[] arr$ = array;
        int len$ = arr$.length;
        for (int i$ = 0; i$ < len$; i$++) {
            int value = arr$[i$];
            // value 사용
        }
        1. 배열의 길이를 len$ 을 통해 미리 계산
        2. 배열 참조를 arr$ 에 저장
        • 장점
          • 루프 마다 배열의 길이를 확인하는 오버헤드가 감소되고
          • 배열 참조를 반복적으로 접근하지 않도록 할 수 있다.
            • 최적화 전: 루프마다 myArray 에 참조
            • 최적화 후 : 한번만 참조
      2. 컬렉션에 대한 최적화

        // 원본 for-each 문
        for (Element e : collection) {
            // e 사용
        }
        ---
        // 최적화 전 (전통적인 Iterator 사용)
        for (Iterator<Element> it = collection.iterator(); it.hasNext(); ) {
            Element element = it.next();
            // element 사용
        }
        ---
        // 최적화 후 (for-each 문 사용 시 컴파일러가 생성하는 코드)
        Iterator<Element> it$ = collection.iterator();
        while (it$.hasNext()) {
            Element element = it$.next();
            // element 사용
        }
        • 차이점
          1. 루프 구조
            • 최적화 이전 : for 루프틑 사용하는 방식
            • 최적화 이후 : while 루프를 상요
          2. Iterator 생성
            • 최적화 이전 : 루프 초기화 부분에서 Iterator 생성
            • 최적화 이후 : 루프 외부에서 Iterator 생성
        • 무슨 의미가 있냐?
          1. Iterator 생성 최적화 부분

            • 루프 외부에서 한번만 생성하여 불필요한 객체 생성을 방지한다
            • 메모리 사용 최적화, GC 부하 감소에 의의
          2. 루프 구조의 단순화

            1. JVM 과 컴파일러가 더 쉽게 최적화할 수 있는 구조라고 한다.

            이건 이해가 안간다. → 사실 지금의 자바같은 경우에는 최적화가 둘다 잘되어 있어 크게 차이가 나지 않을 것 같음.

뭐 작은 컬렉션이나 배열같은 경우 사실 별 의미 없지만, 인덱스가 필요한 경우가 아니라면 for each 를 왠만하면 사용하자.

다만,

for-each 문의 사용이 제한되는 경우도 있음.

  1. 파괴적인 필터링의 경우
    1. 순회하면서 원소를 제거하는 경우
  2. 변형
    1. 원소의 값을 변경하는 경우
  3. 병렬적 반복
    1. 여러 컬렉션을 동시에 순회하는 경우
profile
이전 블로그 : https://oth3410.tistory.com/

0개의 댓글