Enum에 대해 알아보자(+활용)

Entity에 이런 코드를 쓰다가 Enum을 왜 쓰는지 똑바로 모르고 쓰는 중이라는 생각이 들어서 좀 더 알아보기로 했다.

1
2
@Enumerated(EnumType.STRING)
    private Season season; 

1. Enum이란 뭘까

위에서 사용한 @Enumerated(EnumType.STRING) 어노테이션은 엔티티 클래스에서 enum 타입을 데이터베이스에 어떻게 저장할 지 정의해주는 역할을 한다. 즉, enum 값을 문자열로 저장하라는 뜻이다. 그렇다면 enum타입은 뭘까?
enum특정한 상수 집합을 정의하는 자료형이다. 계절, 국가, 회원 등급, 처리 상태, 포켓몬 이름 따위가 있겠다. 미리 값이 정해져 있고, 다른 값이 추가되거나 변경되지 않는 경우 enum으로 정의하기 적합한 자료라고 할 수 있다.
enum을 사용하면 코드의 가독성을 높일 수 있고, 특정 값들이 정해진 범위 안에서만 사용되도록 해 주어서 실수를 줄이게 해준다고 하는데 어떤 점에서 그런지 코드를 살펴보겠다.

1
2
3
4
5
6
7
//1. enum 없이 상수 문자열로 표현한 코드. 가독성이 좋지 못하다  
public class Season {
    public static final String SPRING = "봄";
    public static final String SUMMER = "여름";
    public static final String AUTUMN = "가을";
    public static final String WINTER = "겨울";
} 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//2. 인터페이스로 상수를 정의한 코드.
interface SEASON{
    int SPRING = 1;
    int SUMMER = 2;
}

interface MONTH{
    int JAN = 1;
    int FEB = 2;
}
// 상수끼리 비교하는 논리적으로 잘못된 행위를 하게 될 수도 있다. 
if(SPRING < SUMMER){
    int day = SEASON.SUMMER;
}
//day에 들어간 상수는 SEASON 상수인데, 결국 정수값이기 때문에 에러 없이 switch문이 수행됨 -> 문제가 발생할 수 있다. 
switch (day){
    case MONTH.JAN:
         System.out.println("1월");
         break;
    case MONTH.FEB:
         System.out.println("2월");
         break;
}
1
2
3
4
5
6
//3. 자기 자신 객체를 인스턴트화 한 코드. 다시 가독성이 안 좋아졌고, switch문에서 사용 할 수 없다(switch 조건문에 들어갈 수 있는 데이터 타입이 한정적임)
class Season{
    public final static SEASON SPRING = new SEASON();
    public final static SEASON SUMMER = new SEASON();    
}

그렇다면 enum을 썼을 때는 어떻게 표현 할 수 있을까?

1
2
3
public enum Season{
    SPRING, SUMMER, AUTUMN, WINTER; 
}

이 상태로도 코드는 작동한다. 하지만 일을 하면서 다루게 되는 건 계절처럼 직관적으로 의미를 알 수 있는 데이터가 아닌 경우가 더 많기 때문에 코드 가독성과 협업 편의성을 위해서 설명을 달아주는 게 좋다.

1
2
3
4
public enum Season{
    SPRING("봄"), SUMMER("여름"), AUTUMN("가을"), WINTER("겨울");   
    private final String description;
}

이런 식으로 말이다. 그 밖에도 숫자나 코드처럼 필요한 필드를 추가해서 사용하기도 한다. 권한이나 역할을 정의할 때에도 유용하게 쓸 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum Season{
    SPRING(1,"봄"), SUMMER(2,"여름"), AUTUMN(3,"가을"), WINTER(4,"겨울");   
    private final int code; 
    private final String description;

    Season(int code, String description){
        this.code = code;
        this.description = description; 
    }

    public int getCode(){
        retuen code; 
    }
}

1
2
3
4
5
6
public class SeasonTest {
    public static void main(String[] args) {
        Season ss = Season.SPRING;
        System.out.println("SPRING code: " + ss.getCode()); //출력 : 1  
    }
}

2. Enum에서 데이터를 꺼내 쓰려면

일반 클래스에서 static 상수를 사용하는 것처럼 enum 이름과 값을 직접 참조하면 되는데, 몇 가지 주요 사용법을 예시로 정리해둔다.

  1. enum 값 참조
    1
    2
    3
    4
    5
    6
    public class SeasonTest {
     public static void main(String[] args) {
         Season ss = Season.SPRING;
         System.out.println(ss); //출력 : SPRING  
     }
    }
    
  2. 필드 값 가져오기
    1
    2
    3
    4
    5
    6
    7
    public class SeasonTest {
     public static void main(String[] args) {
         Season ss = Season.SPRING;
         String descriptrion = ss.getDescriptrion();
         System.out.println(descriptrion); //출력 : 봄   
     }
    }
    
  3. switch문에서 사용하기
    enum은 switch문과 함께 사용되는 경우가 많다. 각 enum값에 맞는 동작을 지정할 수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class SeasonTest {
     public static void main(String[] args) {
         Season ss = Season.SPRING;
         switch(ss){
             case SPRING ->  System.out.println("봄입니다.");
             case SUMMER ->  System.out.println("여름입니다.");
         } 
     }
    }
    
  4. 값 비교하기
    enum은 동일성 비교에도 유용하게 쓸 수 있다. enum끼리는 ==로 비교가 가능하고, enum에 정의된 다른 필드를 사용해 값을 비교하는 것도 가능하다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class SeasonTest {
     public static void main(String[] args) {
         Season ss = Season.SPRING;
         String description = "봄"
         if(ss.getDescription().equals(description)){
             System.out.println("봄이라고 합니다.");
         } 
     }
    }
    
  5. enum 값 모두 순회하기 enum에 있는 모든 값을 순회해야 할 때는 values() 메서드를 사용할 수 있다. 이 메서드는 해당 enum 타입의 모든 값을 배열로 반환한다.
    1
    2
    3
    4
    5
    6
    7
    public class SeasonTest {
     public static void main(String[] args) {
         for (Season ss : SeasonTest.values()) {
             System.out.println(ss + ": " + ss.getDescription());
         }
     }
    }
    

3. 결론적으로

기존 방식으로 상수를 사용해도 상관은 없지만, 타입 안정성이나 가독성 향상, 고정된 값 집합 관리의 용이성 등의 이유로 enum을 사용하면 코드의 유지보수성과 안정성이 높아진다.