Search

Item 34. int 상수 대신 열거 타입을 사용하라

생성일
2023/07/27 00:27
챕터
6장 - 열거 타입과 애너테이션

정수 열거 패턴

자바에서 열거 타입을 지원하기 전에는 아래와 같이 정수 상수들을 선언해 사용했었다.
public final static int MONDAY = 1; public final static int TUESDAY = 2; public final static int WEDNESDAY = 3; public final static int THURSDAY = 4; public final static int FRIDAY = 5; public final static int SATURDAY = 6; public final static int SUNDAY = 7;
Java
복사
이와 같은 방식은 타입 안전을 보장할 방법이 없고 가독성과 표현력 전부 좋지 않다.
또한 정수 상수를 문자열로 출력하기가 다소 까다롭다. 값을 출력하거나 디버깅을 할 때에도 단순한 숫자로 보이기 때문에 별로 도움이 되지 않는다.
이에 정수 대신 문자열 상수를 나열하여 사용하는 변형 패턴도 있었는데, 이 변형은 이름 대신 문자열 그대로 하드코딩하게 만들고 오타가 있어도 컴파일러에서 알 수 없으니 런타임 에러가 자주 발생한다.

열거 타입

enum Season { SPRING, SUMMER, FALL, WINTER; } enum Operation { PLUS, MINUS, TIMES, DIVDE; }
Java
복사
C, C++, C# 같은 다른 언어의 열거 타입과 비슷해보이지만, 자바의 열거 타입은 완전한 형태의 클래스로 다른 언어의 열거 타입보다 강력하다.
열거 타입 자체는 클래스이며, 열거 타입 내 상수 하나당 자신의 인스턴스를 하나씩 만들어 public static final 필드로 공개한다. 추가적으로 외부에서 접근할 수 있는 생성자를 제공하지 않아 final과 다를 바 없고, 그렇기에 열거 타입 선언으로 만들어진 인스턴스가 딱 하나씩만 존재한다는 것을 보장할 수 있다.
열거 타입 변수나 매개변수로 받았다면 해당 열거 타입의 상수 중 하나임이 보장되기 때문에, 열거 타입은 컴파일타임 타입 안전성을 제공한다.

열거 타입 매핑

enum Season { SPRING("봄"), SUMMER("여름"), FALL("가을"), WINTER("겨울"); // 문자열을 저장할 필드 private String season; // private 생성자 (싱글톤) private Season(String season) { this.season = season; } public String getSeason() { return season; } }
Java
복사
열거 타입 생성자에서 데이터를 받아 인스턴스 필드에 저장하여, 각각의 상수 인스턴스를 생성할 때 값을 저장하도록 만들면 된다.
public static void main(String[] args) throws Exception { Season s = Season.SUMMER; System.out.println(s.name()); // 열거 객체명 출력 : SUMMER System.out.println(s.getSeason()); // 매핑된 열거 데이터 출력 : 봄 }
Java
복사
이와 같이 데이터와 메서드를 같은 열거 타입으로 각 열거 타입에서 값을 가지고 있게 만들고, 해당 값을 언제든 꺼내어 사용할 수 있다.

열거 타입 확장

각 상수마다 별도의 연산을 수행할 수 있게 만들고 싶다면 아래와 같이 코드를 작성하게 될 것이다.
public enum Operation { PLUS, MINUS, TIMES, DIVDE; // 상수마다의 연산을 수행한다. 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); } }
Java
복사
이 코드는 동작은 하지만, 상수값이 추가될 경우 case문을 추가로 작성해야하고 별로 보기에 좋지 않다.
이에 대한 더 나은 구현 방법은, 열거 타입에 추상 메서드를 선언하고 각 상수별 클래스 몸체(constant-specific class body)에서 자신에 맞게 재정의하는 것이다.
public enum Operation { PLUS {public double apply(double x, double y){return x + y}}, MINUS {public double apply(double x, double y){return x - y}}, TIMES {public double apply(double x, double y){return x * y}}, DIVIDE{public double apply(double x, double y){return x / y}}; public abstract double apply(double x, double y); }
Java
복사