ordinal

배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드로 인덱스를 구할 수 있다.

하지만, 이 방식은 문제가 많다.

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) {
        Set<Plant>[] plantsByLifeCycleArr =
                (Set<Plant>[]) new Set[Plant.LifeCycle.values().length];
        for (int i = 0; i < plantsByLifeCycleArr.length; i++)
            plantsByLifeCycleArr[i] = new HashSet<>();
        
        // 생애주기의 ordinal 값을 인덱스로 사용
        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]);
        }
    }
}

[ 실행 ]

  1. Set 배열을 생성해 생애주기별로 관리한다. 총 3개의 배열이 만들어진다. 각 배열을 순회하여 빈 HashSet으로 초기화 해준다.
  2. plant 들을 배열의 Set에 추가한다. 이때 plant가 가지고있는 LifeCycle 열거타입의 ordinal 값으로 배열의 인덱스를 결정한다. 그 결과 식물의 생애주기 별로 Set에 추가된다.
  3. 결과를 출력한다. 열거 타입의 values로 반환되는 열거 타입 상수 배열의 순서는 ordinal 값으로 결정되기 때문에 Set 배열의 각 Set이 의미하는 생애주기는 values의 순서와 같을 것이다.

Untitled

[ 문제점 ]

  1. 배열은 제네릭과 호환이 되지 않아 [아이템 28] 비검사 형변환을 수행해야 하고 깔끔히 컴파일 되지 않는다.

    Untitled

  2. 배열은 각 인덱스의 의미를 모르니 출력 결과에 직접 레이블을 달아야 한다.

  3. 정수는 열거 타입과 달리 타입 안전하지 않기 때문에 정확한 정숫값을 사용한다는 것을 직접 보증해야 한다.

EnumMap

위의 예시에서 배열은 실질적으로 열거 타입 상수 으로 매핑하는 일을 한다.

따라서 Map 을 사용할 수도 있다.

사실 열거 타입을 키로 사용하도록 설계한 아주 빠른 Map 구현체가 있는데, 바로 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);