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


✅ 1. 문제 제기: Java에서 고정된 값(요일 등)을 int로 표현하는 건 안전할까?

🔥 문제점

public static final int MONDAY = 0;
  • 자바는 final static int 상수를 컴파일 시 숫자 리터럴로 치환

  • 클라이언트 코드에 숫자 자체가 직접 박힘

if (day == Constants.MONDAY) → if (day == 0)
  • 나중에 라이브러리 쪽에서 MONDAY = 1로 바뀌어도, 클라이언트는 여전히 0을 사용 → 의도와 다르게 동작할 위험

  • 따라서 클라이언트도 함께 다시 컴파일해야만 정상 작동함

💣 유지보수에 매우 취약한 구조


✅ 2. enum의 기본 구조와 장점

public enum Day {
    MONDAY, TUESDAY;
}

🔧 자바 컴파일러는 내부적으로 이렇게 변환함:

public final class Day extends Enum<Day> {
    public static final Day MONDAY = new Day("MONDAY", 0);
    public static final Day TUESDAY = new Day("TUESDAY", 1);
    ...
}
  • 각 상수는 public static final 객체 → 싱글톤처럼 단 하나의 인스턴스

  • 생성자는 private이므로 외부에서 인스턴스 생성 불가

  • 상속도 불가 (final class) → 열거 타입은 설계가 고정됨


🌟 장점

✅ 1. 인스턴스 통제

  • 각 상수는 클래스 내부에서 단 하나만 만들어짐 → 외부에서 new로 추가 인스턴스 생성 불가

  • 확장 불가능 (상속 금지)

  • → enum은 본질적으로 싱글톤 집합설계 안정성 + 메모리 안전성

✅ 2. 컴파일 타임 타입 안정성

enum Day { MONDAY, TUESDAY }

public void doSomething(Day day) {
    if (day == Day.MONDAY) { ... }
}
  • dayDay 타입만 받을 수 있음

  • "MONDAY" (문자열)이나 99 (숫자) 같은 잘못된 값은 컴파일 에러

  • → 타입 안정성 보장 + 오타 방지 + IDE 자동완성 가능

✅ 3. 클래스처럼 기능 확장 가능

  • enum은 메서드 정의, 필드 추가 가능

  • toString(), values(), valueOf() 자동 생성

  • implements 인터페이스도 가능

  • → 단순 상수를 넘어서 행위와 데이터가 함께 있는 객체처럼 사용 가능


✅ 3. 고급 기능 예시: enum은 상수 집합 그 이상이다


🎯 예시 1: 상수별 메서드 구현 (constant-specific method implementation)

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; } };

    public abstract double apply(double x, double y);
}
  • 각 상수가 apply() 메서드를 자기 방식대로 오버라이딩

  • switch 없이 동작 분기 가능

  • 동작과 상수를 하나로 결합 → 코드 깔끔 & 확장성 높음


🎯 예시 2: 상수별 데이터 포함

public enum Operation {
    PLUS("+"), MINUS("-");

    private final String symbol;
    Operation(String symbol) { this.symbol = symbol; }

    @Override public String toString() { return symbol; }
}
  • Operation.PLUS"+"라는 출력용 기호도 가짐

  • System.out.println(Operation.PLUS)+

  • → enum에 의미 있는 데이터와 표현력을 함께 담을 수 있음


🎯 예시 3: 전략 열거 타입 (Strategy Enum)

enum PayrollDay {
    MONDAY(PayType.WEEKDAY), SATURDAY(PayType.WEEKEND);

    private final PayType payType;
    PayrollDay(PayType payType) { this.payType = payType; }

    int pay(int mins, int rate) {
        return payType.pay(mins, rate);
    }

    enum PayType {
        WEEKDAY {
            int overtimePay(int mins, int rate) {
                return mins <= 480 ? 0 : (mins - 480) * rate / 2;
            }
        },
        WEEKEND {
            int overtimePay(int mins, int rate) {
                return mins * rate / 2;
            }
        };

        abstract int overtimePay(int mins, int rate);

        int pay(int mins, int rate) {
            return mins * rate + overtimePay(mins, rate);
        }
    }
}

✅ 전략 열거 타입의 장점

  • 상수별 전략(행동)을 별도로 분리해 관리 가능

  • switch 없이 요일마다 다른 급여 계산 로직 처리 가능

  • 기존 enum 수정 없이 전략만 확장하면 됨 → 높은 유지보수성


✅ 4. switch문은 정말 안 써야 할까?

enum의 상수별 동작을 위해선 상수별 메서드 구현이나 전략 열거 타입이 일반적으로 좋지만, 단순히 외부 기능을 추가하고 싶다면 switch도 괜찮음.

public static Operation inverse(Operation op) {
    switch (op) {
        case PLUS: return Operation.MINUS;
        case MINUS: return Operation.PLUS;
        default: throw new AssertionError(op);
    }
}

✅ 5. 언제 enum을 쓰면 좋을까?

☑️ 컴파일 타임에 상수 집합이 정해져 있다면 → enum이 최적의 선택!

예시
적합도

요일, 성별

✅ 매우 적합

행성, 체스 말

✅ 매우 적합

메뉴 옵션, 명령 플래그

✅ 매우 적합

사용자 ID, 채팅 메시지 등 동적 데이터

❌ 부적합


✅ 6. 마무리

자바의 enum은 단순한 상수 묶음이 아닙니다. 행동과 데이터를 함께 가질 수 있는 강력한 타입이며, 코드의 안전성과 가독성을 높이고, 잘못된 값이나 구조 변경에 강한 안정성과 확장성을 제공합니다.

고정된 상수 집합이 필요할 땐, enum이 가장 안전한 선택입니다.


발표자료

https://byumm315.atlassian.net/wiki/external/YzI0ZmQ2ZDViODRlNDViZjhhYmU2ZDYyZWI0OWZmZTg

Last updated