enum으로 닫힌 상태 표현하기
서로 관련된 상수 집합을 문자열이나 정수로 표현하면 허용되지 않은 값도 들어올 수 있습니다.
enum은 가능한 인스턴스를 선언된 상수로 제한하고 각 상수에 상태와 동작을 붙일 수 있습니다.
values로 전체 상수를 순회하고 valueOf로 정확한 이름을 변환합니다.
순서 번호인 ordinal을 저장 형식으로 사용하면 상수 순서 변경에 취약합니다.
이 절에서는 닫힌 상태 집합을 타입으로 만드는 방법을 다룹니다.
enum 상수는 단순한 정수 별칭이 아닙니다. JVM이 해당 enum 클래스를 초기화할 때 한 번 만든 객체이며, 코드에서는 그 정해진 인스턴스를 참조합니다. 그래서 == 비교가 안전하고 EnumSet, EnumMap처럼 상수 집합에 특화된 컬렉션도 사용할 수 있습니다.
상수 이름이 가능한 값을 제한한다
매개변수가 enum 타입이면 호출자는 선언된 상수만 전달할 수 있습니다.
오타 문자열을 실행 중에 찾는 대신 컴파일러의 도움을 받습니다.
상수마다 데이터와 동작을 가질 수 있다
생성자와 필드, 메서드를 선언해 상태 코드나 표시 이름을 함께 보관합니다.
switch가 모든 외부 코드에 흩어지는 것을 줄일 수 있습니다.
EnumStates.java는 지금 설명한 규칙을 실제 값의 변화로 보여 줍니다.
import java.util.Arrays;
public class EnumStates {
enum Priority {
LOW("L", 1), NORMAL("N", 5), HIGH("H", 10);
private final String code;
private final int weight;
Priority(String code, int weight) {
this.code = code;
this.weight = weight;
}
int weight() { return weight; }
static Priority fromCode(String code) {
return Arrays.stream(values())
.filter(value -> value.code.equals(code))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(code));
}
}
public static void main(String[] args) {
System.out.println(Priority.fromCode("H"));
System.out.println(Priority.HIGH.weight());
// Priority.fromCode("X"); // 실행 시 IllegalArgumentException
}
}첫 줄의 HIGH는 외부 코드 H가 enum 상수로 번역된 결과이고, 둘째 줄의 10은 그 상수가 스스로 보유한 가중치입니다. 변환 정책과 상태별 데이터가 한 타입 안에 모여 있다는 점을 확인합니다.
HIGH
10선언 순서와 무관한 code 필드를 사용해 외부 값의 안정된 변환 경계를 만들었습니다.
외부 값은 명시적인 변환 경계를 둔다
valueOf는 이름이 정확히 일치하지 않으면 예외를 냅니다.
사용자 입력은 대소문자와 별칭 정책을 적용한 팩터리 메서드에서 변환합니다.
valueOf("low")가 실패하는 이유는 enum 이름을 사용자 입력 형식으로 설계하지 않았기 때문입니다. 화면이나 저장소의 값이 바뀔 수 있다면 fromCode처럼 그 변화가 들어오는 경계를 따로 두고, 실패 메시지에도 원래 입력을 남깁니다.
Priority parsed = Priority.valueOf("LOW");
System.out.println(parsed);
// Priority.valueOf("low"); // 실행 시 IllegalArgumentException: 정확한 이름 필요
// int stored = Priority.HIGH.ordinal(); // 저장용 식별자로 사용하지 않음
String stableCode = "H"; // enum이 직접 관리하는 명시 코드ordinal은 영구 식별자가 아니다
선언 순서에 따라 값이 바뀌므로 데이터베이스나 파일에 저장하지 않습니다.
안정된 코드 필드를 따로 둡니다.
fromCode에 "N"과 "X"를 차례로 넣어 보세요. 전자는 NORMAL 하나로 수렴하고 후자는 변환 경계에서 즉시 거부되어야 합니다. 그런 다음 상수 선언 순서를 바꿔도 "H"가 계속 HIGH로 읽히는지 확인하면 명시 코드와 ordinal의 차이가 선명해집니다.
enum은 상수를 모아 두는 문법보다 가능한 상태와 그 상태의 규칙을 닫힌 타입으로 표현하는 도구입니다.