열거형 - ENUM

2025. 4. 1. 01:27Java

◎ 문자열과 타입 안정성

-> 어떤 서비스에서 고객의 등급을 BASIC, GOLD, DIAMOND로 나누고 각 등급에 따라 할인율을 다르게 적용한다.

-> 다음은 위 요구 사항에 대한 코드이다.

public class DiscountService {
    public int discount(String grade, int price) {
        int discountPercent = 0; // 할인율

        // 각 등급에 따라 할인율 적용
        if (grade.equals("BASIC")) {
            discountPercent = 10;
        }
        else if (grade.equals("GOLD")) {
            discountPercent = 20;
        }
        else if (grade.equals("DIAMOND")) {
            discountPercent = 30;
        } else {
            System.out.println(grade + " : 할인 X");

        }
        return price * discountPercent / 100;
    }
}

-> 각 회원의 등급을 String으로 받아 해당 문자열과 각 등급(문자열)을 비교해서 등급에 따른 할인율을 적용하도록 했다.

public class StringGradeEx0_1 {
    public static void main(String[] args) {

        int price = 10000;

        DiscountService discountService = new DiscountService();
        int basic = discountService.discount("BASIC", price);
        int gold = discountService.discount("GOLD", price);
        int diamond = discountService.discount("DIAMOND", price);

        System.out.println("BASIC 등급의 할인 금액 : " + basic);
        System.out.println("GOLD 등급의 할인 금액 : " + gold);
        System.out.println("DIAMOND 등급의 할인 금액 : " + diamond);

    }
}

-> 결과

-> 등급에 따라 할인율이 적용된 금액에 출력되었다.

-> 그런데 이 방식에는 문제가 있다. 등급을 String으로 받았기 때문에 만약 오타가 발생한다고 해도 오타가 난 그대로 코드가 실행이 될 것이다. 만약 GOLD를 GOLF라고 입력한다면 에러가 발생하지 않고 그대로 코드가 실행이 되고, 원래대로 실행을 했을 때 GOLD 등급의 고객을 해당 등급에 맞게 할인율을 적용을 해야 할 것이 제대로 할인율이 적용도지 않게 된다.

-> 현재 방식의 문제점을 정리하자면 아래와 같다.

- 타입 안정성 부족 : 문자열은 오타가 발생하기 쉽다. 유효하지 않은 값이 들어갈 수 있다.

- 데이터 일관성 : 문자열로 받기 때문에 다양한 형시의 문자열을 입력할 수 있어 일관성이 떨어진다.

컴파일 시 오류 감지 불가 : 가장 큰 문제다. 오타로 인해 제대로 된 등급이 입력도지 않은 채로 코드가 실행되어 의도와 다른 결과가 나온다.

 

◎ 열거형(Enum Type)

-> 자바에서는 enum이라는 타입을 지원하여 위의 등급과 같은 열거형 패턴을 쉽고 안전하게 사용할 수 있도록 한다.

-> 다음은 등급을 enum type으로 나타낸 것이다.

public enum Grade {
    BASIC,
    GOLD,
    DIAMOND
    ;
}

-> 열거형은 class 대신 enum을 사용한다. 또한 위의 코드는 아래의 코드와 같다.

public class Grade {
    public static final Grade BASIC = new Grade();
    public static final Grade GOLD = new Grade();
    public static final Grade DIAMOND = new Grade();

    // 현재 선언된 클래스 이외의 클래스가 new 키워드를 통해 만들어지지 않도록 private으로 생성자를 제한
    private Grade() {
    }
}

-> 열거형도 클래스이며 외부에서 임의로 생성할 수 없다.

-> 위와 같이 열거형은 클래스이며 각각의 참조값을 가진다.

 

public class EnumRefMain {
    public static void main(String[] args) {
        System.out.println("class BASIC = " + Grade.BASIC.getClass());
        System.out.println("class GOLD = " + Grade.GOLD.getClass());
        System.out.println("class DIAMOND = " + Grade.DIAMOND.getClass());

        System.out.println();

        System.out.println("ref BASIC = " + refValue(Grade.BASIC));
        System.out.println("ref GOLD = " + refValue(Grade.GOLD));
        System.out.println("ref DIAMOND = " + refValue(Grade.DIAMOND));
    }

    private static String refValue(Object grade) {
        return Integer.toHexString(System.identityHashCode(grade));
    }
}

-> 결과

-> 결과를 통해 상수들이 열거형으로 선언한 타입인 Grade 타입을 사용하는 것을 확인할 수 있으며 각 인스턴스도 서로 다른 것을 알 수 있다.

-> 또한 Grade에 정의된 필드(BASIC, GOLD, DIAMOND) 이외에 다른 값이 들어가면 컴파일 시 오류가 발생한다.

-> 다음은 자바의 열거형을 사용해서 기존의 만들었던 DiscountService를 수정한 코드다.

public class DiscountService {
    public int discount(Grade grade, int price) {
        int discountPercent = 0; // 할인율

        // 각 등급에 따라 할인율 적용
        if (grade == Grade.BASIC) {
            discountPercent = 10;
        }
        else if (grade == Grade.GOLD) {
            discountPercent = 20;
        }
        else if (grade == Grade.DIAMOND) {
            discountPercent = 30;
        } else {
            System.out.println(grade + " : 할인 X");

        }
        return price * discountPercent / 100;
    }
}
public class EnumEx3_1 {
    public static void main(String[] args) {

        int price = 10000;

        DiscountService discountService = new DiscountService();

        int basic = discountService.discount(Grade.BASIC, price);
        int gold = discountService.discount(Grade.GOLD, price);
        int diamond = discountService.discount(Grade.DIAMOND, price);

        System.out.println("BASIC 등급의 할인 금액 : " + basic);
        System.out.println("GOLD 등급의 할인 금액 : " + gold);
        System.out.println("DIAMOND 등급의 할인 금액 : " + diamond);
    }
}

-> 결과

-> 이렇게 열거형을 사용하면 문자열을 사용했을 때 발생하는 오타 문제나 컴파일 시 오류 감지를 할 수 없는 문제를 해결할 수 있다. 열거형의 장점은 아래와 같이 정의할 수 있다.

 

- 타입 안정성 향상 : 열거형은 정의된 상수들로만 구성되므로 유효하지 않은 값(열거형에 정의되지 않은 상수)은 입력될 가능성이 없다. 입력된다면 컴파일 오류가 발생한다.

- 간결성 및 일관성 : 코드가 간결해지고 열거형에 정의된 상수만 사용되기 떄문에 데이터의 일관성이 보장된다.

- 확장성 : 만약 새로운 회원 등급을 추가한다면 열거형에 그냥 추가하고자 하는 상수만 추가하면 된다.

 

※ 열거형은 java.lang.Enum을 자동으로 상속받는다. 따라서 다른 클래스를 추가로 상속받을 수 없다.

※ 열거형은 인터페이스를 구현할 수 있으며 추상 메서드를 선언하고, 구현할 수 있다.

 

★ 참고 및 출처

스프링 DB 1편 - 데이터 접근 핵심 원리 

'Java' 카테고리의 다른 글

중첩 클래스 ,내부 클래스1  (0) 2025.04.07
래퍼, Class 클래스  (0) 2025.03.27
String 클래스  (0) 2024.11.18
불변객체  (0) 2024.10.31
Object 클래스  (0) 2024.10.29