Post

[JAVA] ENUM - 열거형

[JAVA] ENUM - 열거형

열거형 - ENUM

열거형(Enum Type)을 이해하기 위한 예제를 만들어보자

고객을 3개의 등급으로 나누고, 상품 구매 시 등급별로 할인을 적용한다. (소수점 버림)

  • BASIC → 10% 할인
  • GOLD → 20% 할인
  • DIAMOND → 30% 할인

할인등급을 String 으로 표현했을 때의 문제점

  • 문자열은 오타, 유효하지 않은 값 입력가능
  • 타입 안정성 없음, 데이터 일관성 부족, 컴파일 시점에 오류 검출 불가
1
2
3
4
5
6
7
discount("GOLD", 10000);       // 정상
discount("gold", 10000);       // 오타
discount("VIP", 10000);        // 존재하지 않는 등급

public int discount(int price) {
    return price * discountPercent / 100;
}

문자열 상수(public static final) 사용

1
2
3
4
5
public class StringGrade {
    public static final String BASIC = "BASIC";
    public static final String GOLD = "GOLD";
    public static final String DIAMOND = "DIAMOND";
}

장점

  • 오타를 줄이고 IDE 자동완성 가능.
  • 컴파일 시점에 상수 오타는 검출됨.

문제

  • 여전히 String 타입이라 "VIP" 같은 임의 문자열을 막을 수 없음.
  • discount() 호출자가 반드시 StringGrade의 상수를 사용한다는 보장이 없음.

타입 안전 열거형 패턴 (Type-Safe Enum Pattern)

문자열을 대신해 타입으로 상태를 표현

열거 가능한 상태를 직접 표현해 정해진 값만 사용하게 제한

1
2
3
4
5
6
7
public class ClassGrade {
    public static final ClassGrade BASIC = new ClassGrade();
    public static final ClassGrade GOLD = new ClassGrade();
    public static final ClassGrade DIAMOND = new ClassGrade();

    private ClassGrade() {} // 외부에서 인스턴스 생성 금지
}

private 생성자의 필요성

  • 외부에서 new ClassGrade() 불가능하게 막음.
  • 오직 내부에서 정의된 BASIC, GOLD, DIAMOND만 존재하게 제한 → “열거형”

사용

1
discount(ClassGrade.GOLD, 10000); // 타입이 ClassGrade이므로 안전

장점

  • 타입 안전성ClassGrade 타입만 허용하므로 잘못된 값 전달 불가
  • 데이터 일관성 보장
  • 컴파일 타임 검증 가능

직접 구현한 타입-안전 열거형의 한계)

  • 코드량이 많음
  • 새로운 등급 추가 시 코드 수정 필요
  • 비교적 번거롭고 자바에서 제공하는 enum보다 불편함

ENUM

이런 문제를 해결하고, 타입 안정성과 편의성을 모두 갖춘 기능이 자바 열거형(enum) 이다. enum 은 위에서 설명한 타입 안전 열거형 패턴을 자바 언어 차원에서 공식 지원하는 문법

클래스지만 제한이 많은 상수 전용 클래스라 생각

1
2
3
public enum Grade {
    BASIC(10),GOLD(20),DIAMOND(20);
}

열거형 내부 상태와 메서드 활용

grade 안에 할인율 필드를 넣고, 계산 책임 이관

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum Grade {
    BASIC(10),GOLD(20),DIAMOND(20);

    private final int discountPercent;

    //생성자를 통해서 필드에 값을 저장
    Grade(int discountPercent) {
        this.discountPercent = discountPercent;
    }

    //값을 조회하기 위한 메서드 열거형도 클래스라 메서드 추가 가능
    public int getDiscountPercent() {
        return discountPercent;
    }
}
  • 상태(discountPercent) + 동작(discount()) = 객체 지향
  • enum이 단순한 상수가 아닌, 행동도 가지는 객체처럼 사용 가능

리팩토링 효과

기존

1
int discount = DiscountService.discount(Grade.GOLD, price)

변경 후

1
int discount = Grade.GOLD.discount(price);

→ DiscountService 클래스 자체가 불필요해짐

반복 출력 및 동적 사용 가능

1
2
3
for (Grade grade : Grade.values()) {
    System.out.println(grade.name() + " 등급 할인: " + grade.discount(10000));
}
  • values() → 모든 enum 상수 목록
  • name() → enum 이름
  • 새 enum 상수가 추가되더라도 메인 코드 변경 불필요

ordinal()의 위험성

  • ordinal()은 선언 순서를 숫자로 반환 (0부터)
  • enum의 순서가 바뀌면 모든 값이 밀려서 버그 발생 가능
  • 예: DB에 ordinal() 저장하면 enum 순서 바뀔 때 문제 생김
  • 따라서 ordinal() 대신 enum 이름 자체를 저장하거나 별도 코드 사용 권장

열거형 요약

  • 열거형은 클래스다 (단, 다른 클래스 상속 불가, Enum만 자동 상속)
  • 메서드 추가 가능, 상태 보유 가능
  • 캡슐화 + 타입 안정성 + 가독성 + 유지보수성 모두 잡을 수 있는 기능
  • 실무에서 enum은 상태, 타입 구분, 전략 표현, DB 코드 매핑 등에 자주 사용됨
  • 자바의 enum은 singleton이므로 .equals() 대신 == 비교가 더 일반적

새로운 등급 추가 쉽다

1
PLATINUM(25)
1
Grade.PLATINUM.discount(10000) // → 2500

Grade enum에 PLATINUM만 추가하면 기존 코드는 수정 없이 확장 가능

→ OCP (개방-폐쇄 원칙) 잘 지켜짐!


출처: 김영한의 실전 자바 - 중급 1편

This post is licensed under CC BY 4.0 by the author.

Trending Tags