ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Item 37. ordinal 인덱싱 대신 EnumMap을 사용하라
    Book/Effective Java 3E 2023. 2. 24. 19:00
    반응형
    package effectivejava.chapter6.item37;
    import java.util.*;
    import static java.util.stream.Collectors.groupingBy;
    import static java.util.stream.Collectors.toSet;
    
    // EnumMap을 사용해 열거 타입에 데이터를 연관시키기
    
    // 식물을 아주 단순하게 표현한 클래스
    class Plant {
        enum LifeCycle { ANNUAL, PERENNIAL, BIENNIAL }
    
        final String name;
        final LifeCycle lifeCycle;
    
        Plant(String name, LifeCycle lifeCycle) {
            this.name = name;
            this.lifeCycle = lifeCycle;
        }
    
        @Override public String toString() {
            return name;
        }
    
        public static void main(String[] args) {
            Plant[] garden = {
                new Plant("바질",    LifeCycle.ANNUAL),
                new Plant("캐러웨이", LifeCycle.BIENNIAL),
                new Plant("딜",      LifeCycle.ANNUAL),
                new Plant("라벤더",   LifeCycle.PERENNIAL),
                new Plant("파슬리",   LifeCycle.BIENNIAL),
                new Plant("로즈마리", LifeCycle.PERENNIAL)
            };
    
            // 코드 37-1 ordinal()을 배열 인덱스로 사용 - 따라 하지 말 것!
            Set<Plant>[] plantsByLifeCycleArr =
                    (Set<Plant>[]) new Set[Plant.LifeCycle.values().length];
            for (int i = 0; i < plantsByLifeCycleArr.length; i++)
                plantsByLifeCycleArr[i] = new HashSet<>();
            for (Plant p : garden)
                plantsByLifeCycleArr[p.lifeCycle.ordinal()].add(p);
            // 결과 출력
            for (int i = 0; i < plantsByLifeCycleArr.length; i++) {
                System.out.printf("%s: %s%n",
                        Plant.LifeCycle.values()[i], plantsByLifeCycleArr[i]);
            }
    
            // 코드 37-2 EnumMap을 사용해 데이터와 열거 타입을 매핑한다.
            Map<Plant.LifeCycle, Set<Plant>> plantsByLifeCycle =
                    new EnumMap<>(Plant.LifeCycle.class);
            for (Plant.LifeCycle lc : Plant.LifeCycle.values())
                plantsByLifeCycle.put(lc, new HashSet<>());
            for (Plant p : garden)
                plantsByLifeCycle.get(p.lifeCycle).add(p);
            System.out.println(plantsByLifeCycle);
    
            // 코드 37-3 스트림을 사용한 코드 1 - EnumMap을 사용하지 않는다!
            System.out.println(Arrays.stream(garden)
                    .collect(groupingBy(p -> p.lifeCycle)));
    
            // 코드 37-4 스트림을 사용한 코드 2 - EnumMap을 이용해 데이터와 열거 타입을 매핑했다.
            System.out.println(Arrays.stream(garden)
                    .collect(groupingBy(p -> p.lifeCycle,
                            () -> new EnumMap<>(LifeCycle.class), toSet())));
        }
    }

     

    코드 37-1

    • 배열은 제네릭과 호환되지 않으니 비검사 형변환을 수행해야 하고 깔끔히 컴파일되지 않을 것입니다.
    • 배열은 각 인덱스의 의미를 모르니 출력 결과에 직접 레이블을 달아야 합니다.
    • 정확한 정숫값을 사용한다는 것을 직접 보증해야 합니다. (정수는 열거 타입과 달리 타입 안전하지 않습니다.)

     

    코드 37-2

    • EnumMap(열거 타입을 키로 사용하도록 설계한 Map 구현체)을 사용한 코드입니다.
    • 더 짧고 명료하고 안전하고 성능도 원래 버전과 비등합니다.
    • 코드 37-1의 문제점을 모두 해결합니다.

     

    코드 37-3

    • 스트림을 사용해 맵을 관리하는 코드입니다.
    • EnumMap이 아닌 고유한 맵 구현체를 사용했기에 EnumMap을 써서 얻은 공간과 성능 이점은 사라집니다.

     

    코드 37-4

    • EnumMap을 이용해 데이터와 열거 타입을 매핑한 스트림 기반 코드입니다.

     

    배열의 인덱스를 얻기 위해 ordinal을 쓰는 것은 일반적으로 좋지 않으니, 대신 EnumMap을 사용하라.

    다차원 관계는 EnumMap<..., EnumMap<...>>으료 표현하라.

     

    [참고 정보]

    이펙티브 자바 Effective Java 3/E 도서 [조슈아 블로크 ]

    이펙티브 자바 깃허브 저장소

    <이펙티브 자바, 3판> 번역 용어 해설

    반응형

    댓글

Designed by Tistory.