본문 바로가기

Hub Development/Java

[Java] 자바 Enum 특징과 활용

728x90

📌 Enum 이란?


🔹 Enum은 Enumeration의 줄임말로, 관련된 상수들의 집합을 나타낸다. Enum은 프로그래밍에서 상수를 쉽게 관리하고 사용할 수 있게 해준다. 클래스가 상수만으로 이루어진 경우 클래스나 인터페이스로 선언할 필요없이 Enum을 활용하여 네이밍 충돌이나 불필요한 상수의 증가와 같은 단점을 보완할 수 있다.

 

클래스 내에 상수를 선언하는 대신 enum으로 선언하면, 이 객체가 상수의 집합임을 명확하게 나타내고 이를 통해, 코드의 가독성을 높이고 IDE의 지원을 받을 수 있으며 타입 안정성을 확보할 수 있다.

 

📑 Enum 특징


🔹기존 클래스에서 상수를 정의한다면 아래와 같이 final 제어자를 활용해서 상수를 정의했을 것이다. final 제어자를 사용하여 값을 한 번 할당하면 변경할 수 없도록 만들고, static을 사용하면 메모리에 한 번만 할당되어 모든 인스턴스가 동일한 값을 공유하도록 한 코드이다.

하지만, 이런식으로 상수를 선언하게 되는 경우 클래스 내부에 많은 상수가 선언되면서 코드의 가독성이 저하될 수 있다. 특히, 클래스가 커지고 복잡해질수록 이러한 상수들을 찾기가 어려워질 수 있다. 

public class ConstantsHandler {

    public static final int MIN_DATE_NUMBER = 1;
    public static final int MAX_DATE_NUMBER = 31;
    public static final int MIN_MONTH_NUMBER = 1;
    public static final int MAX_MONTH_NUMBER = 12;

    public static void main(String[] args) {
        int date = 14;
        int month = 2; 

        if (isValidDate(date) && isValidMonth(month)) {
            System.out.println("The date " + date + "/" + month + " is valid.");
        } else {
            System.out.println("The date " + date + "/" + month + " is invalid.");
        }
    }
    
    private static boolean isValidDate(int date) {
        return date >= MIN_DATE_NUMBER && date <= MAX_DATE_NUMBER;
    }

    private static boolean isValidMonth(int month) {
        return month >= MIN_MONTH_NUMBER && month <= MAX_MONTH_NUMBER;
    }
}

 

이러한 방식 대신 자바에서는 아예 상수만을 다루는 enum 타입 클래스를 만들어 배포했다. JAVA의 enum은 인터페이스와 같이 독립된 특수한 클래스로 구분한다. 즉, 일종의 객체이기 때문에 힙(heap) 메모리에 저장되며 각 enum 상수들은 별개의 메모리 주소값을 가짐으로써 완벽히 독립된 상수를 구성할 수 있다. 이러한 Enum의 장점은 아래와 같다.

1. 상수의 그룹화가 가능하다.

🔹메뉴에 대한 관리를 하고자 했을 때 메뉴의 이름, 가격, 타입을 한번에 관리할 수 있다면 매우 편리할 것이다. 이러한 내용을 클래스로 작성하고자 한다면 Map 자료구조를 활용하여 작성할 수 있겠지만 Enum과 비교한다면 연관된 상수들을 그룹화하여 표현할 수 있는 Enum에 비해 가독성이 떨어지고 자바에서 지원해주는 Enum의 타입안정성에 비해 오류가 날 가능성이 높다. 하지만, Enum을 활용한다면 아래와 같이 그룹화하여 나타낼 수 있다.

package christmas.domain;

public enum MenuManager {

    YANGSONGEE_SOUP("양송이수프", 6000, "에피타이저"),
    TAPAS("타파스", 5500, "에피타이저"),
    CAESAR_SALAD("시저샐러드", 8000, "에피타이저"),
    T_BONE_STEAK("티본스테이크", 55000, "메인"),
    BBQ_RIB("바비큐립", 54000, "메인"),
    SEAFOOD_PASTA("해산물파스타", 35000, "메인"),
    CHRISTMAS_PASTA("크리스마스파스타", 25000, "메인"),
    CHOCOLATE_CAKE("초코케이크", 15000, "디저트"),
    ICE_CREAM("아이스크림", 5000, "디저트"),
    ZERO_COLA("제로콜라", 3000, "음료"),
    RED_WINE("레드와인", 60000, "음료"),
    CHAMPAGNE("샴페인", 25000, "음료");

    private final String menu;
    private final int cost;
    private final String group;

    MenuManager(String menu, int cost, String group) {
        this.menu = menu;
        this.cost = cost;
        this.group = group;
    }

    public static MenuManager getMenuManager(String orderedMenu) {
        for (MenuManager menuManager : MenuManager.values()) {
            if (menuManager.getMenu().equals(orderedMenu)) {
                return menuManager;
            }
        }

        return null;
    }

    public String getMenu() {
        return menu;
    }

    public int getCost() {
        return cost;
    }

    public String getGroup() {
        return group;
    }
}

2. Enum 클래스를 구현하는 경우 상수 값과 같이 유일하게 하나의 인스턴스가 생성되어 사용된다.

🔹 Enum 클래스를 구현하는 경우, 각 상수 값은 해당 enum 클래스의 유일한 인스턴스로 생성된다. 이는 Java에서 enum이 내부적으로 싱글톤 패턴을 사용하기 때문이다. 싱글톤 패턴은 애플리케이션 전역에서 단 하나의 인스턴스만 존재하도록 보장하는 디자인 패턴이다.

 

예를 들어, 다음과 같은 enum을 봤을 때.

public enum Direction {
    NORTH,
    SOUTH,
    EAST,
    WEST
}

 

이 경우, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST 각각의 값은 해당 enum 클래스의 인스턴스이다. 이들은 프로그램 전체에서 유일하게 하나의 인스턴스만 존재하며, 이러한 인스턴스는 런타임에 자동으로 생성된다. 따라서, enum 클래스를 사용하면 상수 값이 유일한 인스턴스로 생성되어 사용되며, 이를 통해 안전하고 효율적인 프로그래밍을 할 수 있습니다.

3. 생성자를 호출하지 않는다.

🔹Java의 enum은 사전에 정의된 상수의 집합으로 고정되어 있으며, enum 상수들은 해당 enum 클래스의 정적 멤버로 취급되어 프로그램이 시작될 때 모든 상수들이 미리 생성되어 메모리에 올라간다. 또한,  enum은 컴파일러가 자동으로 생성자를 만들어주는데 이 생성자는 private으로 선언되어 있어 외부에서 직접 접근할 수 없다. 이렇게 되면 사용자가 직접 생성자를 호출하지 않아도 되므로, enum 상수들은 프로그램 전체에서 단일 인스턴스 즉, 싱글톤으로 공유될 수 있다.

public class OtherClass {
    public void someMethod() {
        String menu = MenuManager.YANGSONGEE_SOUP.getMenu();
        int cost = MenuManager.TAPAS.getCost();
        String group = MenuManager.CAESAR_SALAD.getGroup();
        // 다른 작업 수행
    }
}

👻  Enum 내부 메서드


🔹 Enum은 java.lang.Enum 클래스를 기본적으로 상속받고 있기 때문에 아래의 세 가지 메소드를 지원한다. (부모 클래스의 메소드라 사용 가능하다.)

public enum Rank {
    	THREE(3, 4_000),
    	FOUR(4, 10_000),
    	FIVE(5, 30_000);
    	
    	private final int match;
    	private final int money;
    	private int count;
    	
    	Rank(int match, int money) {
    		this.match = match;
    		this.money = money;
    	}
    
    	public void plusCount() {
    		this.count++;
    	}
    }

1. values()

🔹 values() 는 Enum 클래스가 가지고 있는 모든 상수 값을 배열의 형태로 리턴 한다. 참고로 단순히 String 의 형태로 단순 반환하는 것이 아니라 인스턴스를 반환하는 것이다. 즉 Enum 클래스가 가지고 있는 모든 인스턴스를 배열에 담아 반환하는 것이다.

    public static void main(String[] args) {
    		Rank[] values = Rank.values();
    		for(int i = 0; i< values.length; i++) {
    			System.out.println(values[i]);
    		}
    }

    // 실행 결과 : THREE, FOUR, FIVE

2. valueOf()

🔹 valueOf() 메서드는 String 을 파라미터로 받는데 인자로 들어온 String 과 일치하는 상수 인스턴스가 존재하면 그 인스턴스를 반환한다. 이 또한 마찬가지로 단순히 문자열을 반환하는 것이 아니라 인자로 들어온 문자열과 일치하는 인스턴스를 반환하는 것이다.

    public static void main(String[] args) {
    		System.out.println(Rank.valueOf("THREE"));
    	}

    // 실행 결과 : THREE

3. ordinal()

🔹 Enum 클래스 내부에 있는 상수들의 Index 를 리턴하는 메소드이다. 배열과 마찬가지로 0부터 인덱스가 시작하며 인덱스의 length 는 상수의 수 - 1 이다.

    public static void main(String[] args) {
    		Rank[] values = Rank.values();
    		for(int i = 0; i< values.length; i++) {
    			System.out.println(values[i] + "인덱스는 : " + values[i].ordinal());
    		}
    	}

    // 실행 결과

    THREE인덱스는 : 0
    FOUR인덱스는 : 1
    FIVE인덱스는 : 2

 

🧪 추가적인 Enum 장점


◈ 코드가 단순해지며 가독성이 좋아진다

◈ 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타낼 수 있다.

◈ 자체 클래스 상수와 달리 switch문에서도 사용할 수 있다

◈ 단순 상수와 비교해 IDE의 적극적인 지원을 받을 수 있다 (자동완성, 오타검증, 텍스트 리팩토링 등등)

◈ enum은 본질적으로 Thread safe인 싱글톤 객체 이므로 싱글톤 클래스를 생성하는데에도 사용된다

 

📸 참조


https://velog.io/@kyle/%EC%9E%90%EB%B0%94-Enum-%EA%B8%B0%EB%B3%B8-%EB%B0%8F-%ED%99%9C%EC%9A%A9