[이펙티브 자바] 아이템 37. ordinal 인덱싱 대신 EnumMap을 사용하라

June·2022년 2월 27일
0

[이펙티브자바]

목록 보기
34/72
// 식물을 아주 단순하게 표현한 클래스 (226쪽)
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;
    }

정원에 심은 식물들을 배열 하나로 관리하고, 이들을 생애주기(한해살이, 여러해살이, 두해살이)별로 묶어보자. 생애주기별로 총 3개의 집합을 만들고 정원을 한 바퀴 돌며 각 실물을 해당 집합에 넣는다.어떤 프로그래머는 집합들을 배열 하나에 넣고 생애주기의 ordinal 값을 그 배열의 인덱스로 사용하려 할 것이다.

안좋은 코드

Set<Plant>[] plantsByLifeCycle = (Set<Plant>[]) new Set[Plant.LifeCycle.values().length];

for (int i = 0; i < plantsByLifeCycle.length; i++)
    plantsByLifeCycle[i] = new HashSet<>();
    
for (Plant p : garden)
    plantsByLifeCycle[p.lifeCycle.ordinal()].add(p);

// 결과 출력
for (int i = 0; i < plantsByLifeCycle.length; i++) {
    System.out.printf("%s: %s%n", Plant.LifeCycle.values()[i], plantsByLifeCycle[i]);
}

배열은 제네릭과 호환되지 않으니(아이템 28) 비검사 형변환을 수행해야 하고 깔끔히 컴파일되지 않는다.(?)
또 정확한 정숫값을 사용한다는 것을 직접 보장해야 한다는 점이다. 잘못된 값을 사용하면 잘못된 동작을 수행하거나 ArrayIndexOutOfBoudnsException을 던질 것이다. 

여기서 배열은 실질적으로 열거 타입 상수를 값으로 매핑하는 일을 한다.  그러면 Map을 사용할 수 있는데, **열거 타입을 키로 사용하도록 설계된 아주 빠른 Map 구현체가 EnumMap**이다. 

``` java
Map<Plat.LifeCyfcle, Set<Plat>> platsByLifeCycle =  new EnumMap<>(Play.LifeCycle.class);

for (Plant.LifeCycle lc : Plant.LifeCycle.values())
    playsByLifeCycle.put(lc, new HashSet<>());

for (Plant p : garden)
    plantsByLifeCycle.get(p.lifeCycle).add(p);
System.out.println(plantsByLifeCycle);

안전하지 않은 형변환은 쓰지 않고, 맴의 키인 열거 타입이 그 자체로 출력용 문자열을 제공하니 출력 결과에 직접 레이블을 달 일도 없다. 또 배열 인덱스를 계산하는 과정에서 오류가 날 가능성도 없다.

EnumMap의 성능이 ordinal을 쓴 배열과 비슷한 이유는 내부에서 배열을 사용하기 때문이다.

스트림을 사용한 코드

System.out.println(Arrays.stream(garden)
    .collect(groupingBy(p -> p.lifeCycle, () -> new EnumMap<>(LifeCycle.class), toSet())));

스트림을 사용하면 EnumMap만 사용했을 때와 살짝 다르다. EnumMap 버전은 언제나 식물의 생애주기당 하나씩의 중첩 맵을 만들지만, 스트림 버전에서는 해당 생애주기에 속하는 식물이 있을 때만 만든다.

0개의 댓글