티스토리 뷰
기존의 방식
- 타입 안전을 보장할 방법이 없다.
- 표현력이 좋지 않다.
- 동등 연산자 == 로 비교하더라도 아무런 경고가 없다.
- 문자열로 출력하기가 까다롭다.
// 34-1. 정수 열거 패턴
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;
public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;
// 문자열 열거 패턴
public static final String APPLE_FUJI = "APPLE_FUJI";
public static final String APPLE_PIPPIN = "APPLE_PIPPIN";
public static final String APPLE_GRANNY_SMITH = "APPLE_GRANNY_SMITH";
public static final String ORANGE_NAVEL = "ORANGE_NAVEL";
public static final String ORANGE_TEMPLE = "ORANGE_TEMPLE";
public static final String ORANGE_BLOOD = "ORANGE_BLOOD";
- 정수 열거 패턴보다 더 안좋다.
- 하드코딩하게 만든다.
- 오타가 있어도 컴파일에서 확인이 불가능하니 런타임에 오류가 생긴다.
새로운 방식
// 34-2. 열거 타입
public enum Apple {
FUJI, PIPPIN, GRANNY_SMITH
}
public enum Orange {
NAVEL, TEMPLE, BLOOD
}
- 일종의 클래스이다.
- 컴파일타임 타입 안전성을 제공한다.
- 상수 하나당 자신의 인스턴스를 하나씩 만들어 public static final 필드로 공개한다.
- 안에 구조로 보면 이렇게 public static final 로 되어있다.
- 클라이언트가 인스턴스를 직접 생성하거나 확장할 수 없으니 인스턴드들은 딱 하나씩만 존재한다.
- 다시말해 인스턴스 통제, 싱글턴이다.
- 거꾸로 열거 타입은 싱글턴을 일반화한 형태라고 볼 수 있다.
- 열거 타입에는 toString(), Object 메서드들을 높은 품질로 구현해 놨다.
- Comparable, Serializable을 구현해놨다.
열거타입의 메서드와 필드
- 열거 타입에는 어떤 메서드도 추가할 수 있다.
- 단순하게는 상수 모음일 뿐이지만, 실제로는 클래스이므로 고차원의 추상 개념 하나를 완벽히 표현해낼 수도 있다.
// 34-3. 여덟개의 행성을 나타낸 열거 타입
public enum Planet {
MERCURY(3.302e+23,2.439e6),
VENUS(4.869e+24,6.052e6),
EARTH(5.975e+24, 6.378e6),
MARS(6.419e+23,3.393e6),
JUPITER(1.899e+27,7.149e7),
SATURN(5.685e+26,6.027e7),
URANUS(8.683e+25,2.556e7),
NEPTUNE(1.024e+26,2.477e7);
private final double mass;
private final double radius;
private final double surfaceGravity;
private static final double G = 6.67300E-11;
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
this.surfaceGravity = G * mass / (radius * radius);
}
// getter ...
public double surfaceWeight(double mass) {
return mass * surfaceGravity;
}
}
- 열거 타입 상수 각각을 특정 데이터와 연결지으려면 생성자에서 데이터를 받아 인스턴스 필드에 저장하면된다.
- 열거 타입은 근본적으로 불변이라 모든 필드는 final 이어야 한다.
- 필드는 private 으로 하고 접근자 메서드를 둔다.
- 열거 타입에서는 values() 를 제공하는데 자신안에 정의된 상수들의 값을 배열에 담아 반환한다.
- 열거 타입을 선언한 클래스 혹은 그 패키지에서만 유용한 기능은 private이나 package-privat 메서드로 구현한다.
상수별 메서드 구현
public enum Operation {
PLUS {
@Override
public double apply(double x, double y) {
return x + y;
}
},
MINUS {
@Override
public double apply(double x, double y) {
return x - y;
}
},
TIMES {
@Override
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
@Override
public double apply(double x, double y) {
return x / y;
}
},
;
public abstract double apply(double x, double y);
}
- apply() 가 상수 선언 바로 옆에 있으니 새로운 상수를 추가할 때도 apply()를 재정의 해야한다는 사실을 깜빡하기 힘들다.
- 또한 apply() 가 추상메서드이므로 재정의하지 않았다면 컴파일 오류로 알려준다.
전략 열거 타입
// 급여명세서
public enum PayrollDay {
MONDAY(WEEKDAY),
TUESDAY(WEEKDAY),
WEDNESDAY(WEEKDAY),
THURSDAY(WEEKDAY),
FRIDAY(WEEKDAY),
SATURDAY(WEEKEND),
SUNDAY(WEEKEND),
;
private final PayType payType;
PayrollDay(PayType payType) {
this.payType = payType;
}
int pay(int minutesWorked, int payRate) {
return payType.pay(minutesWorked, payRate);
}
// 전략 열거 타입
enum PayType {
WEEKDAY {
@Override
int overtimePay(int minsWorked, int payRate) {
return minsWorked <= MINS_PER_SHIFT ? 0 :
(minsWorked - MINS_PER_SHIFT) * payRate / 2;
}
},
WEEKEND {
@Override
int overtimePay(int minsWorked, int payRate) {
return minsWorked * payRate / 2;
}
};
abstract int overtimePay(int mins, int payRate);
private static final int MINS_PER_SHIFT = 8 * 60;
int pay(int minsWorked, int payRate) {
int basePay = minsWorked * payRate;
return basePay + overtimePay(minsWorked, payRate);
}
}
}
- 기존의 switch 문은 간결하지만 관리 관점에서는 위험한 코드이다, 왜냐면 새로운 값을 열거 타입에 추가하면 case 문에 잊지 말고 넣어줘야 한다.
- 이렇게 전략을 선택하도록 하면 switch 문보다 더 안전하고 유연하다.
열거 타입을 언제 쓰라는 건가 ?
- 필요한 원소를 컴파일타임에 다 알 수 있는 상수 집합일때
- ex. 태양계 행성, 한 주의 요일, 체스 말...
결론
- 열거 타입은 확실히 정수 상수보다 더 읽기 쉽고 안전하고 강력하다.
- 열거 타입에서는 switch 문 대신 상수별 메서드 구현을 사용하자.
- 열거 타입 상수 일부가 같은 동작을 공유한다면 전략 열거 타입 패턴을 사용하자.
'책 > 이펙티브자바' 카테고리의 다른 글
아이템38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라 (0) | 2021.08.29 |
---|---|
아이템35. ordinal 메서드 대신 인스턴스 필드를 사용하라 (0) | 2021.08.28 |
아이템27. 비검사 경고를 제거하라 (0) | 2021.08.24 |
아이템26. 로 타입은 사용하지 말라 (0) | 2021.08.24 |
아이템25. 톱레벨 클래스는 한 파일에 하나만 담으라 (0) | 2021.08.24 |
링크
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 드림코딩
- 가상 면접 사례로 배우는 대규모 시스템 설계 기초
- js promise
- 이펙티브자바 아이템60
- 백기선 스터디
- JPA 연관관계 매핑
- 김영한 http
- http
- GCP
- js array
- 프로그래머스
- 이펙티브자바 아이템59
- REST API
- 백준
- 이펙티브자바
- Spring Security
- JS 딥다이브
- java
- 모던자바스크립트
- 패스트캠퍼스 컴퓨터공학 완주반
- js api
- 킹수빈닷컴
- dreamcoding
- HTTP 완벽 가이드
- HTTP 완벽가이드
- 이펙티브자바 스터디
- 프로그래머스 SQL
- 김영한 JPA
- BOJ
- ㅇㄷㅇㅈ
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함