일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 프로그래머스
- android architecture component
- Kotlin
- FLUTTER
- C
- Flutter TextField
- 알고리즘
- Android P
- Android
- UWP
- 코틀린
- kodility
- 안드로이드 구글맵
- Django REST framework
- Django REST
- android push
- livedata
- dart
- C++
- flutter firestore
- mfc
- Rxjava2
- C/C++
- RxAndroid
- RxJava
- 안드로이드
- Python
- Java
- Django REST Android
- NDK
- Today
- Total
개발하는 두더지
[Effective Java 규칙33] ordinal을 배열 인덱스로 사용하는 대신 EnumMap을 이용하라 본문
[Effective Java 규칙33] ordinal을 배열 인덱스로 사용하는 대신 EnumMap을 이용하라
Effective Java 2/E 책과 구글링을 통해 내용을 정리하고 개인적인 견해가 포함된 글입니다.
일의 중요도를 나타내는 간단한 클래스가 있다.
class Work {
enum Importance {
LOW, MEDIUM, HIGH, CRITICAL;
}
String name;
Importance importance;
Work(String name, Importance importance) {
this.name = name;
this.importance = importance;
}
}
일의 배열 Work[] 이 있고, 일의 중요도에 따라 나열한다고 생각해보자. 중요도별 집합을 4개 만들고, 일을 각 중요도에 맞게 집합에 넣어주면 된다.
public static void main(String[] args) {
Work[] works = new Work[5];
works[0] = new Work("work1", Importance.LOW);
works[1] = new Work("work2", Importance.MEDIUM);
works[2] = new Work("work3", Importance.HIGH);
works[3] = new Work("work4", Importance.CRITICAL);
works[4] = new Work("work5", Importance.LOW);
Set<Work>[] importanceByType = (Set<Work>[]) new Set[Importance.values().length];
for(int i = 0; i < importanceByType.length; i++)
importanceByType[i] = new HashSet();
for(Work w : works)
importanceByType[w.importance.ordinal()].add(w);
for(int i = 0; i < importanceByType.length; i++) {
System.out.printf("%s %s\n", Work.Importance.values()[i], importanceByType[i]);
}
}
책에서도 사용하지 말라고 하는 방식이며 문제점도 많다.
1. 배열은 제네릭과 호환되지 않으므로 (규칙25) 배열을 쓰려면 무점검 형변환 (Set<Work>[]) 이 필요하다.
2. 배열의 인덱스는 무엇을 가리키는지 모르므로, 출력 결과에 붙일 레이블을 별도로 만들어야 한다. 위 예제에서는 Work class에서 toString을 재정의하여 name을 리턴하도록 하면 Work의 이름으로 결과를 출력할 수 있다.
3. enum의 ordinal 값으로 배열을 참조할 때 정확한 int 값으로 나와야하는데 틀린값을 쓰는 경우 심각한 문제가 발생할 수 있다.
사실 enum 상수를 키로 사용할 목적으로 만들어진 성능이 아주 우수한 Map이 있는데 바로 EnumMap이다.
Map<Importance, Set<Work>> workByType = new EnumMap<>(Work.Importance.class);
for(Work.Importance i : Work.Importance.values())
workByType.put(i, new HashSet<>());
for(Work w : works)
workByType.get(w.importance).add(w);
System.out.println(workByType);
// {LOW=[work1, work5], MEDIUM=[work2], HIGH=[work3], CRITICAL=[work4]}
소스코드도 짧고, 형 안정적이고, ordinal을 이용해 만든 코드와 성능면에서도 비등하다. 무점검 형변환 코드도 없고, Map에 보관된 키가 enum이니 출력 가능한 문자열로 알아서 변환되기 때문에 출력을 위한 레이블을 따로 만들 필요도 없다. 배열 인덱스를 계산하다가 오류가 발생할 가능성도 없다.
EnumMap이 ordinal 값을 배열 인덱스로 쓰는 기법과 속도면에서 별 차이가 없는 것은 EnumMap이 이미 그런 배열을 내부적으로 사용하고 있기 때문이다. 메모리 요구량이나 수행 성능 측면에서 손해를 보는 일도 없고, 안전해지고, 유지보수가 쉬워진다.
그러므로 ordinal 값을 배열의 인덱스로 사용하는 방법은 적절치 않고, EnumMap을 활용해야한다.
'Java,Android' 카테고리의 다른 글
[Effective Java 규칙39] 필요하다면 방어적 복사본을 만들라 (0) | 2018.10.15 |
---|---|
[Effective Java 규칙37] 자료형을 정의할 때 표식 인터페이스를 사용하라 (0) | 2018.10.15 |
[Effective Java 규칙32] 비트 필드(bit field) 대신 EnumSet을 사용해라 (0) | 2018.10.12 |
[Effective Java 규칙31] enum ordinal 대신 객체 필드를 사용하라 (0) | 2018.10.12 |
[Effective Java 규칙30] int 상수 대신 enum을 사용하라 (0) | 2018.10.08 |