반응형
public class Herb {
enum Type{ ANNUAL, PERENNIAL, BIENNIAL }
final String name;
final Type type;
Herb(String name, Type type){
this.name = name;
this.type = type;
}
@Override
public String toString() {
return name;
}
}
//ordinal 값을 배열 첨자로 이용하는 방법
//지양
class HerbTest1{
Herb[] garden;
public void test1() {
Set<Herb>[] herbsByType =
(Set<Herb>[]) new Set[Herb.Type.values().length];
//Indexed by Herb.Type.ordinal()
for( int i = 0 ; i < herbsByType.length ; i++) {
herbsByType[i] = new HashSet<Herb>();
}
for( Herb h : garden ) {
herbsByType[h.type.ordinal()].add(h);
}
//결과 출력
for ( int i = 0 ; i < herbsByType.length ; i++) {
System.out.println(Herb.Type.values()[i] +" "+ herbsByType[i]);
}
}
}
· 배열을 제네릭과 호환되지 않으므로(규칙 25) 배열을 사용하려면 무점검 형변환해야한다.
· 배열은 무엇을 나타내는지 모르므로 라벨과 같이 출력해야한다.
· ordinal값의 Enum만큼의 int는 형안전성이 보장되지 않는다.
· 틀린 값을 쓰면 ArrayIndexOutOfBoundsException예외가 발생한다.
//EnumMap을 사용해 enum상수별 데이터를 저장하는 프로그램
class HerbTest2{
Herb[] garden;
public void test1() {
Map<Herb.Type, Set<Herb>> herbsByType =
new EnumMap<Herb.Type , Set<Herb>>(Herb.Type.class);
//한정적 자료형 토큰 : 실행시점 제네릭 자료형 정보를 제공 (규칙 29)
for(Herb.Type t : Herb.Type.values()) {
herbsByType.put(t, new HashSet<Herb>());
}
for(Herb h : garden) {
herbsByType.get(h.type).add(h);
}
//결과 출력
System.out.println(herbsByType);
}
}
· Enum상수를 키로 사용할 목적으로 설계된 Map : EnumMap
· 무점검 형변환, 레이블을 만들 필요가 없다.
ordinal을 두개를 사용하여 enum상수와의 관계를 표현하는 코드
//상전이 예제 클래스
enum Phase{
SOLID, LIQUID, GAS;
public enum Transition{
MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT;
//아래 배열의 행은 상전이 이전상태를 나타내는 enum 상수의 ordinal값을 첨자로 사용하고
//열은 상전이 이후 상태를 나타내는 enum상수의 ordinal값을 첨자로 사용한다.
private static final Transition[][] TRANSITTIONS = {
{null, MELT, SUBLIME},
{FREEZE,null,BOIL},
{DEPOSIT, CONDENSE, null}
};
//특정 상전이 과정을 표현하는 enum상수를 반환
public static Transition from(Phase src, Phase dst) {
return TRANSITTIONS[src.ordinal()][dst.ordinal()];
}
}
}
//상전이 예제 클래스
enum PhaseEnum{
SOLID, LIQUID, GAS;
public enum Transition{
MELT(SOLID,LIQUID),
FREEZE(LIQUID,SOLID),
BOIL(LIQUID,GAS),
CONDENSE(GAS,LIQUID),
SUBLIME(SOLID,GAS),
DEPOSIT(GAS,SOLID);
private final PhaseEnum src;
private final PhaseEnum dst;
Transition(PhaseEnum src, PhaseEnum dst){
this.src = src;
this.dst = dst;
}
//상전이 맵 초기화
private static final Map<PhaseEnum, Map<PhaseEnum, Transition>> m =
new EnumMap<PhaseEnum, Map<PhaseEnum, Transition>>(PhaseEnum.class);
static {
//세개의 빈 안쪽 맵을 값으로 사용하는 바깥 맵을 초기화
for(PhaseEnum p : PhaseEnum.values()) {
m.put(p, new EnumMap<PhaseEnum, Transition>(PhaseEnum.class));
}
//각각의 상전이 명칭 상수에 보관된 상전이 이전상태와
//이후 상태정보를 사용해서 안쪽맵 초기화
for(Transition trans : Transition.values()) {
m.get(trans.src).put(trans.dst, trans);
}
}
public static Transition from(PhaseEnum src, PhaseEnum dst) {
return m.get(src).get(dst);
}
}
}
자료형
Map<PhaseEnum, Map<PhaseEnum, Transition>>
PLASMA의 새로운 상태를 추가하려고 할때
관계된 상전이 : 이온화(IONIZATION) : GAS → PLASMA,
역이온화(DEIONIZATION) : PLASMA → GAS
배열 예제에 추가하려 했을 때
1. Phase에 새로운 상수 추가
2. Phase.Transition에 새 상수 두개 추가
3. 원래 9개원소를 갖는 배열을 2차원 배열로 수정
Enum 예제에 추가할 때
1. Phase에 새로운 상수 추가
2. Phase.Transition에 새 상수 두개 추가
결론
· ordinal값을 배열 첨자로 사용하지말고 EnumMap을 사용하라.
반응형
'IT > Programming' 카테고리의 다른 글
<Effective Java> RULE 31 ordinal 대신 객체 필드를 사용하라 (0) | 2023.04.27 |
---|---|
<Effective Java> RULE 32 비트필드 대신 EnumSet을 사용하라 (0) | 2023.04.27 |
<Effective Java> RULE 34 확장 가능한 enum을 만들어야 한다면 인터페이스를 이용하라 (0) | 2023.04.27 |
<Effective Java> RULE 35 작명 패턴 대신 어노테이션을 사용하라 (0) | 2023.04.27 |
<Effective Java> RULE 36 Override 어노테이션은 일관되게 사용하라 (0) | 2023.04.27 |