Java Enum 이전에는 상수를 정의하기 위해서 보통 static final 로 선언된 정수 값을 사용했다.
public class Days {
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
}
위 코드를 보면 Days 클래스에 final로 상수를 정의해서 사용한다.
만약 이렇게 코드를 작성했을때의 단점은 뭘까?
위 상수는 단순히 정수 값으로 취급되기 때문에 다른 값과의 혼용 가능성이 존재한다.
int day = Days.MONDAY;
day = 100; // 컴파일 에러가 발생하지 않음 (잘못된 값 허용)
정해진 값외에 잘못된 값을 사용하는 경우에도 컴파일 오류로 잡아낼 수 없다.
if (day == 1) { // '1'이 무엇을 의미하는지 알기 어려움
System.out.println("월요일입니다.");
}
상수에 정수 값을 할당하게 된다면 코드 상에서 숫자가 의미하는 바를 파악하기 어렵다. 직접 숫자 값들을 비교해야 하기 때문에 코드의 직관성이 떨어질 수 있다.
새로운 상수를 추가(예를 들면 Holiday) 하거나 기존 상수를 수정하면 코드 전반에 걸쳐 변경이 필요할 수 있고, 상수에 추가적인 정보를 부여하려면 별도의 구조를 정의해야 하기때문에 번거롭다.
이러한 한계를 해결하기 위해 Java 1.5에서 Enum이 도입되었다.
Enum 은 상수를 타입화하고 객체화하여 더 안전하고 확장이 가능한 방식으로 상수를 관리할 수 있게 해주는 도구이다.
열거형이라고 보통 말하는데 열거형이란 말 그대로 사용 가능한 값들을 나열해 놓은 객체를 말한다. Enum을 사용하면 그 안에 명시되어 있는 값들을 미리 정의하고 관리할 수 있게 한다.
한정된 값들만 들어가 있는 특별한 상자라고 생각하면 된다.
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
상수들을 열거형으로 선언하고, 각 상수들을 독립된 개체로 관리한다.
IDE에서도 보면 아래와 같이 독립된 Enum 파일로 생성할 수 있는게 보여진다.

primitive 타입이 아닌 reference 타입으로 분류되기 때문에 각 Enum은 메모리의 heap에 저장되고, 고유한 메모리 주소를 가질 수 있다.
→ 상수간에 충돌 없이 독립적으로 관리될 수 있다.
Enum은 클래스처럼 동작하기 때문에 필드와 메서드를 정의할 수 있다.
월~금요일은 기본 출근일이기 때문에 요율 1을 반환하고, 주말은 주말 수당을 붙여 2를 반환하는 Enum을 만들어보자.
public enum Day {
MONDAY("Weekday", 1),
TUESDAY("Weekday", 1),
WEDNESDAY("Weekday", 1),
THURSDAY("Weekday", 1),
FRIDAY("Weekday", 1),
SATURDAY("Weekend", 2),
SUNDAY("Weekend", 2);
private final String description; // 요일의 설명 (Weekday, Weekend)
private final int payRatio; // 출근(1) 또는 주말 수당(2)
// Enum 생성자
Day(String description, int payRatio) {
this.description = description;
this.payRatio = payRatio;
}
// Getter 메서드
public String getDescription() {
return description;
}
public int getPayRatio() {
return payRatio;
}
public String getWorkType() {
return this.payRatio == 1 ? "출근일" : "주말근무";
}
}
이처럼 Enum을 단순한 상수 정의를 넘어선 객체처럼 활용할 수 있다.
public static final int MONDAY = 1; // 수당을 따로 정의해야 함
int payRatio = getPayRatio(MONDAY); // 의미가 모호
int payRatio = Day.MONDAY.getPayRatio(); // 가독성이 높음| 메서드 | 설명 | 예제 | 출력 |
|---|---|---|---|
values() | Enum에 정의된 모든 상수값을 배열로 반환 | Day.values() | [MONDAY, TUESDAY, ... SUNDAY] |
valueOf(String) | Enum 이름과 일치하는 상수를 반환 | Day.valueOf("MONDAY") | MONDAY |
name() | Enum 상수의 이름을 반환 | Day.MONDAY.name() | MONDAY |
ordinal() | 선언된 순서(0부터 시작)를 반환 | Day.MONDAY.ordinal() | 0 |
compareTo(Enum) | Enum 간의 순서를 비교 | Day.MONDAY.compareTo(Day.FRIDAY) | -4 |
⭐ Enum을 비교할 땐 뭐가 가장 효율적일까?
== 연산자를 사용하는 방법
==연산자는 Enum 상수 간의 참조 동일성(reference equality)을 검사한다.
Enum 상수는 Java에서 싱글톤으로 관리되기 때문에 항상 동일한 객체를 참조한다.
equals()를 사용하는 것은 값의 동일성을 검사하는데 Enum에서는 ==와 equals가 동일하게 동작한다. 하지만 Null을 비교할 땐 주의가 필요하기 때문에 참조동일성을 비교하는 ==연산자를 사용하는것이 더 효율적이라고 할 수 있다.
⭐ Flag를 쓸 때 Boolean 대신 Enum을 사용하라
상품 배송 상태를 배송 전과 배송 후를 가를 수 있는
isDelivered라는 boolean값으로 표현했다고 하자.
그러나 비즈니스 로직이 확장되어 ‘출고 완료’, ‘배송 중’, ‘배송 완료’, ‘배송 취소’ 등 다양한 상태가 추가되면 boolean 값으로는 이러한 상태를 모두 표현하기 어렵다.
이때 Enum을 활용하면 좋다.// 1. boolean 값으로 표기 public class Order { private boolean isDelivered; } // 2. enum 으로 표기 public enum ShippingStatus { READY_FOR_SHIPMENT, // 출고 준비 중 SHIPPED, // 출고 완료 IN_TRANSIT, // 배송 중 DELIVERED, // 배송 완료 CANCELED // 배송 취소 } public class Order { private ShippingStatus shippingStatus; }추가 확장에 대해서만 효율적인것이 아니라 명확한 의미 측면에서도 좋다. boolean 타입이었다면 false 상태가 무엇을 의미하는지는 모호하다.
또한 Enum은 타입안정성을 제공한다. 두 매개변수가 모두 boolean일 때, 실수로 순서를 바꿔 전달하는 위험을 줄일 수 있다. Enum은 매개변수 간의 혼동을 방지해 안전한 코드를 작성하는 데 도움을 줄 수 있다.
결론
여러 상태를 다뤄야 하거나 매개변수 간 혼동을 방지해야 하는 상황에서 Enum은 Boolean보다 훨씬 안전하고 효율적인 선택이다.