-
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 도서 [조슈아 블로크 저]
반응형'Book > Effective Java 3E' 카테고리의 다른 글
Item 36. 비트 필드 대신 EnumSet을 사용하라 (0) 2023.02.18 Item 35. ordinal 메서드 대신 인스턴스 필드를 사용하라 (0) 2022.12.29 Item 34. int 상수 대신 열거 타입을 사용하라 (0) 2022.12.28 Item 33. 타입 안전 이종 컨테이너를 고려하라 (1) 2022.12.23 Item 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라 (0) 2022.12.20