Enum

Jaca·2021년 11월 15일

이넘에 대해 알아보자 !!

자바의 정석에서도 Enum에 대한 부분이 분명히 있었지만,
자바의 정석에서는 Enum에 대해 그렇게 와닫지 않았다. (이해 못했단 뜻 ㅎ)

아마 Enum의 사용법을 대강이라도 본 적이 없었다면 아마 손 대지도 못했을 것 같다.

그래서 Enum에 대해 제대로 알아보자

1. Enum?

Enum이란 관련 있는 상수의 집합이며, 열거형이라고도 한다.
자바에서는 final로 기본 자료형의 값을 고정할 수 있으며, 이를 상수(Constant) 라고 한다.
어떤 class가 상수의 집합으로 이루어져 있다면, Enum으로 선언 하는 것이 명시적으로 좋다.

2. 왜 Enum을 ?

Enum을 사용하지 않은 상수의 선언은 아래와 같다.

public class Day {
    private final static int MONDAY = 1;
    private final static int TUSEDAY = 2;
    private final static int WEDNESAY = 3;
    private final static int THURDAY = 4;
    private final static int FRIDAY = 5;
    private final static int SATURDAY = 6;
    private final static int SUNDAY = 7;
    
    public static void main(String[] args) {
        int day= MONDAY;
        
        switch (day) {
        case MONDAY : ...
        case TUSEDAY : ...
        
        ...
        }
    }
}

위와 같이 final과 static을 사용하여 한 번만 할당되고 바꿀수 없게 해줄 수 있다.
하지만 요일 뿐만 아니라 다른 상수의 선언이 필요해진다면 상수가 너무 많아지고 상수에 대한 정보를 직관적으로 알 수 없다.
또 만약 중복된 이름으로 정의된 상수는 컴파일러가 오류로 판단한다.
그래서 class 또는 인터페이스를 사용하여 각각의 집합끼리 상수를 정의할 수 있다.

interface DAY {
    int MONDAY = 1;
    int TUESDAY = 2;
    int WEDNESDAY = 3;
    int THURDAY = 4;
    int FRIDAY = 5;
    int SATURDAY = 6;
    int SUNDAY = 7;
}

interface MONTH {
    int JANUARY = 1;
    int FEBRUARY = 2;
    int MARCH = 3;
    int APRIL = 4;
    int MAY = 5;
    int JUNE = 6;
    int JULY = 7;
    int AUGUST = 8;
    int SEPTEMBER = 9;
    int OCTOBER = 10;
    int NOVEMBER = 11;
    int DECEMBER = 12;
}

public class Example {
    public static void main(String[] args) {
        if(DAY.MONDAY == MONTH.JUNUARY) {
            System.out.println("두 상수는 같습니다.");
        }
    }
}

위와 괕이 두 개의 상수 집합을 만들 수 있다.
Interface를 사용해서 public static final 같은 속성을 생략하여 코드의 가독성을 높일 수 도 있다.
하지만 이렇게 DAY.MONDAY == MONTH.JUNUARY 같이 다른 집합의 상수를 비교하는 것은 런타임 단계에서 예기치 못한 문제를 발생시킬 수 있다.

그래서 Interface를 class로 바꾼다면,
각각의 상수들은 데이터 타입은 같지만 서로 다른 데이터 값을 가지게 된다.
이렇게 되면 DAY.MONDAY == MONTH.JUNUARY 같은 비교는 다른 데이터 타입이기 때문에 불가능 하고,
switch문에서 사용되는 데이터 타입은 제한적이기 때문에 switch문의 사용이 힘들다.

이런 문제점을 해결하기 위해 Enum을 사용한다.

3. Enum 사용하기

enum Day {
    MONDAY, TUESDAY, WEDNSEDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}

enum Month {
    JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OTCOBER, NOVEMBER, DECEMBER;
}

public class Example {
    public static void main(String[] args) {
        Day day = Day.MONDAY;

        switch (day) {
            case MONDAY: ...
            case TUESDAY: ...
        }
    }
}

Enum을 사용하면 위와 같이 상수의 이름을 나열하기만 하면 상수가 정의 된다.
또한, switch 문의 레이블은 조건으로 넘어온 데이터 타입을 알고 있다.
그래서 각각의 레이블에서 Enum의 데이터 타입을 생략할 수 있다.

Enum을 사용 하면 아래의 장점이 있다.

  • 코드가 단순해지며 가독성이 좋다.
  • 인스턴스의 생성과 상속을 방지한다.
  • 키워드가 Enum이라면, 구현 의도가 상수의 열거임을 분명하게 알 수 있다.

4. Enum과 생성자

Enum의 각 상수에 추가 속성을 부여할 수 있다.
위의 예제와 같이 각각의 요일에 1~7의 값을 부여한다면, 아래와 같다

enum Day {
    MONDAY(1), TUESDAY(2), WEDNSEDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);

    int value;

    private Day(int value) {
        this.value = value
    }

    public int getValue() {
        return value;
    }
}

생성자의 파라미터를 통해 추가 속성을 Enum 클래스의 필드에 설정해주고,
Getter를 통해 해당 속성을 필요할 때 가져다 쓸 수 있게 한다.
이렇게 메서드나 필드를 Enum 타입에 추가하면 Enum 상수에 어떤 데이터를 연관시킬 수 있다.

Enum의 생성자가 private 인 이유는,
Enum 타입은 고정된 상수들의 집합으로, 런타임 시점이 아닌 컴파일 시점에 모든 값을 알고 있어야한다.
즉 다른 패키지나 클래스에서 Enum 타입에 접근해서 동적으로 어떤 값을 정해줄 수 없다.
따라서 컴파일 시에 타입안정성이 보장된다.
이를 위해 생성자의 접근제어자를 private로 설정해야하고,
이를 통해 Enum타입을 실질적으로 final처럼 만들어 준다.

profile
I am me

0개의 댓글