배열이나 리스트에서 원소를 꺼낼 때 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]);
}
}
}
[ 실행 ]
Set
배열을 생성해 생애주기별로 관리한다. 총 3개의 배열이 만들어진다. 각 배열을 순회하여 빈 HashSet
으로 초기화 해준다.Set
에 추가한다. 이때 plant가 가지고있는 LifeCycle 열거타입의 ordinal
값으로 배열의 인덱스를 결정한다. 그 결과 식물의 생애주기 별로 Set
에 추가된다.values
로 반환되는 열거 타입 상수 배열의 순서는 ordinal
값으로 결정되기 때문에 Set
배열의 각 Set
이 의미하는 생애주기는 values
의 순서와 같을 것이다.[ 문제점 ]
배열은 제네릭과 호환이 되지 않아 [아이템 28] 비검사 형변환을 수행해야 하고 깔끔히 컴파일 되지 않는다.
배열은 각 인덱스의 의미를 모르니 출력 결과에 직접 레이블을 달아야 한다.
정수는 열거 타입과 달리 타입 안전하지 않기 때문에 정확한 정숫값을 사용한다는 것을 직접 보증해야 한다.
위의 예시에서 배열은 실질적으로 열거 타입 상수 를 값 으로 매핑하는 일을 한다.
따라서 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);