ordinal 메서드(아이템 35)
- 배열 혹은 리스트에서 원소를 꺼내기 위해 이를 사용해 인덱스를 얻는 경우가 있음
- ordinal 메서드는 인스턴스가 가진 EnumName의 Index 번호를 넘겨줌
- 코드 37-1의 문제 겸, ordinal 메서드 사용의 문제
- 배열과 제네릭은 호환되지 않기에 비검사 형변환 수행을 해야 하며, 이로 깔끔히 컴파일되지 않을 것임
- 배열은 숫자로 된 데이터로 인덱스의 의미를 모르니 출력 겨로가에 레이블을 달아야 함
- 정숫값을 사용한다는 것을 직접 보증해야 함
- 정수는 열거 타입과 달리 안전하지 않음
- 잘못된 값을 사용할 경우
- 그대로 잘못된 수행을 하거나 (ㅋㅋㅋ 최악의 상황 ㅠ)
- 운이 좋을 경우 ArrayIndexOutOfBoundsException을 던짐
- 잘못된 값을 사용할 경우
위 문제 해결 :: EnumMap
- 열거 타입 상수를 값으로 매핑해 Map으로 사용할 수 있음
- 열거 타입을 키로 사용하도록 설계되어 빠른 처리 가능
- 예제 코드 37-2 참고
- EnumMap을 사용해 짧고, 명료하며, 안전하고 성능도 원래 버전과 비등하게 만들 수 있음
- 맵의 키인 열거 타입 자체로 출력용 문자열을 제공해 결과에 직접 레이블을 작성하지 않아도 됨
- 배열 인덱스 계산 과정에서 오류 가능성 원천 보 ㅇ쇄됨
- ordinal 메서드보다 좋은 이유는 EnumMap 내부로 구현 방식을 숨겨 안전성과 배열의 성능을 얻은 것
- 코드를 보면 [ Plant.LifeCycle.class ]로 EnumMap이 생성자를 받는데, 이는 받는 키 타입의 Class 객체는 한정적 타입 토큰으로 런타임 제네릭 타입 정보를 제공함 (아이템 33)
스트림을 사용하면 코드를 더 줄일 수 있음
- 코드 37-3 참고
- 고유 맵 구현체를 사용해 EnumMap을 사용해 얻는 공간과 성능의 이점이 사라짐
- EnumMap을 이용해 데이터와 열거 타입을 매핑하여 최적화를 시킬 수 있음 [코드 37-4]
- 스트림 사용으로 인한 EumMap과의 차이
- EnumMap은 언제나 식물 생애주기당 하나씩의 중첩 맵을 만듦
- Stream은 해당 생애주기에 속하는 식물이 있을 때만 만듦
- 다시 한 번 더 이야기하지만 ordinal을 사용하면 배열 인덱스의 관계를 알 수 없으며, IndexOutOfBoundsException, NullPointerException이 발생함. 아니 그냥 이상하게 동작할 수 있음.
인덱스가 잘 못 나오면 그냥 엉뚱한거 쭉 해버리는 거임. - 위와 같은 이유로 EnumMap을 사용하는게 훨씬 좋음. [코드 37-6]
- 전이 하나를 얻기 위해 이전 상태와 이후 상태가 필요하니 맵 두개를 중첩해 쉽게 해결 가능함
- 내부 맵은 이전 상태 전이를 연결하고
외부 맵은 이후 상태와 안쪽 맵을 연결함
액체가 녹았다가 얼을 때, 그걸 생각하면 됨. 고체 -> 액체, 액체 -> 고체 변하듯 맵도 이전 상태와 이후 상태를 연결해 주어야 함. - (무슨 말인지 다시 이해를 해야겠으나..) 전이 전후의 두 상태를 전이 열거 타입 Transition으로 입력 받아, 이 Transition 상수들로 중첩된 EnumMap을 초기화하면 됨
- 코드 37-6
- Map<Phase, Map<Phase, Transition>>
- 이전 상태에서 이후 상태에서 전이로의 맵에 대응
- 한 마디로.. 이전 상태를 이후 상태로 대응 시켜라 맞춰라 그런 뜻
- 여기서 java.util.stream.Collector 두 개를 차례로 사용
- groupingBy ==> 전이를 이전 상태 기준으로 묶음
- toMap ==> 이후 상태를 전이에 대응시키는 EnumMap 생성
- 병합 함수인 (x, y) -> y는 선언하고 사용하지는 안흔ㄴ데, 이는 EnumMap을 얻으려면 맵 팩터리가 필요하며, 위 수집기들은 점층적 팩터리를 제공하기 때문
- 원소 수정이 일어날 경우
- EnumMap은 상태 목록에 무언가를 추가하고 전이 목록에 추가하면 끝임
- 배열로 선언했을 때와 다르게 배열로 구현되어 발생하는 낭비된 공간과 시간이 거의 없이 명확하고 안전하게 유지보수가 쉬움
- Map<Phase, Map<Phase, Transition>>
핵심 정리
- 배열 인덱스를 얻기 위해 ordinal 메서드를 쓰는 것은 일반적으로 좋지 않으니 EnumMap을 사용할 것
- 다차원 관계는
- EnumMap< ..., EnumMap<...>> 으로 표현
'Programming > JAVA' 카테고리의 다른 글
[Java Secure coding] 자바 시큐어코딩 기법 (2) - SQL Injection (0) | 2021.07.31 |
---|---|
[Java secure coding] 자바 시큐어코딩 기법 (1) (0) | 2021.07.31 |
[Effective JAVA 3SE] item 36: 비트 필드 대신 EnumSet을 사용하라 (0) | 2021.07.19 |
[Effective JAVA 3SE] item 28: 배열보다는 리스트를 사용하라 (0) | 2021.07.11 |
[Effective JAVA] item 22 : 인터페이스는 타입을 정의하는 용도로만 사용하라 (0) | 2021.07.03 |