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; // 붉은색 오렌지
- **타입 안전을 보장할 방법이 없다.**
- 예를 들어서 오렌지를 건네야 하는 메서드에 사과를 보내고 동등 연산자(==)로 비교해도 아무런 경고가 없다.
- 표현도 애매하다.
- 사과용 상수의 이름은 `APPLE_`, 오렌지용 상수는 `ORNAGE_` 라는 prefix를 사용해 이름 충돌을 방지한다.
- 문자열로 출력하기도 다소 까다롭다.
- 출력하거나 디버거로 살펴봐도 결국 숫자로만 보이기 때문..
- 정수 열거그룹을 순회하기도 힘들다.
## 열거 타입(enum type)
```java
public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
public enum Orange { NAVEL, TEMPLE, BLOOD }
열거 타입의 장점?
자바의 열거 타입은 완전한 형태의 클래스다.
상수 하나당 자신의 인스턴스를 하나씩 만들어 public static final 필드로 공개!
열거 타입은 밖에서 접근할 수 있는 생성자를 제공하지 않으므로 사실상 final 이다.
그러므로 인스턴스들은 딱 하나씩만 존재한다. #3
열거 타입은 컴파일타임 타입 안전성을 제공한다.
Apple 열거 타입을 매개변수로 받는 메서드를 선언했다면, 건네받은 참조는 Apple의 세 가지 값 중 하나임이 확실하다.
다른 타입의 값을 넘기려 하면 컴파일 오류가 발생한다.
열거 타입의 toString 메서드는 출력하기에 적합한 문자열을 제공한다.
임의의 메서드나 필드를 추가할 수 있고 임의의 인터페이스를 구현하게 할 수 있다.
열거 타입의 예시
데이터와 메서드를 갖는 열거 타입
아래와 같이 태양계의 여덞 행성에 대한 열거 타입을 만드는 것도 그리 어렵지 않다.
enum Planet {
MERCURY(3.302e+23, 2.439e6),
VENUS(4.869e+24, 6.052e6),
EARTH(5.975e+24, 6.378e6);
// ...
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;
surfaceGravity = G * mass / (radius * radius);
}
public double mass() { return mass; }
public double radius() { return radius; }
public double surfaceGravity() { return surfaceGravity; }
public double surfaceWeight(double mass) {
return mass * surfaceGravity; // F = ma
}
}
열거 타입 상수 각각을 특정 데이터와 연결지으려면, 생성자에서 데이터를 받아 인스턴스 필드에 저장하면 된다.
열거 타입은 근본적으로 불변이라 모든 필드는 final이어야 한다. #17
열거 타입은 자신 안에 정의된 상수들의 값을 배열에 담아 반환하는 정적 메서드 values를 제공한다.
public class EffectiveJava34 {
public static void main(String []args){
double earthWeight = Double.parseDouble("150");
// 요렇게 손쉽게 사용 가능!
double mass = earthWeight / Planet.EARTH.surfaceGravity();
// 모든 enum 요소를 탐색할 수 있다.
for(Planet p : Planet.values()) {
System.out.printf("%s에서의 무게는 %f이다.%n", p, p.surfaceWeight(mass));
}
}
}
일반 클래스와 마찬가지로, 외부에 노출해야할 합당한 이유가 없다면 private or package-private로 만들자! #15
상수가 더 다양한 기능을 제공했으면 한다?
예를 들어 사칙연산 계산기의 연산 종류를 열거 타입으로 선언하고, 실제 연산까지 열거 타입 상수가 직접 수행하게 한다면?
enum Operation {
PLUS, MINUS, TIMES, DIVIDE;
public double apply(double x, double y) {
switch(this) {
case PLUS: return x + y;
case MINUS: return x - y;
case TIMES: return x * y;
case DIVIDE: return x / y;
}
throw new AssertionError("알 수 없는 연산: " + this);
}
}
열거(enum) 타입을 제공하기 이전의 상수 선언
public static final int ORANGE_NAVEL = 0; // 귤? public static final int ORANGE_TEMPLE = 1; // 귤? public static final int ORANGE_BLOOD = 2; // 붉은색 오렌지
열거 타입의 장점?
public static final
필드로 공개!열거 타입의 예시
데이터와 메서드를 갖는 열거 타입
아래와 같이 태양계의 여덞 행성에 대한 열거 타입을 만드는 것도 그리 어렵지 않다.
열거 타입은 자신 안에 정의된 상수들의 값을 배열에 담아 반환하는 정적 메서드
values
를 제공한다.상수가 더 다양한 기능을 제공했으면 한다?
예를 들어 사칙연산 계산기의 연산 종류를 열거 타입으로 선언하고, 실제 연산까지 열거 타입 상수가 직접 수행하게 한다면?
상수별 메서드 구현(constant-specific method implementation)
// get 하는 방식 public static Optional fromString(String symbol) {
return Optional.ofNullable(stringToEnum.get(symbol));
}
전략 열거 타입 패턴
정리하면!