Enum

Dev.Dana·2024년 12월 26일

Java

목록 보기
7/7
post-thumbnail

Enum의 등장 배경

Java Enum 이전에는 상수를 정의하기 위해서 보통 static final 로 선언된 정수 값을 사용했다.

public class Days {
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
}

위 코드를 보면 Days 클래스에 final로 상수를 정의해서 사용한다.

만약 이렇게 코드를 작성했을때의 단점은 뭘까?

1. 타입 안정성 부족

위 상수는 단순히 정수 값으로 취급되기 때문에 다른 값과의 혼용 가능성이 존재한다.

int day = Days.MONDAY;
day = 100; // 컴파일 에러가 발생하지 않음 (잘못된 값 허용)

정해진 값외에 잘못된 값을 사용하는 경우에도 컴파일 오류로 잡아낼 수 없다.

2. 가독성과 의미 전달 부족

if (day == 1) { // '1'이 무엇을 의미하는지 알기 어려움
    System.out.println("월요일입니다.");
}

상수에 정수 값을 할당하게 된다면 코드 상에서 숫자가 의미하는 바를 파악하기 어렵다. 직접 숫자 값들을 비교해야 하기 때문에 코드의 직관성이 떨어질 수 있다.

3. 확장성의 어려움

새로운 상수를 추가(예를 들면 Holiday) 하거나 기존 상수를 수정하면 코드 전반에 걸쳐 변경이 필요할 수 있고, 상수에 추가적인 정보를 부여하려면 별도의 구조를 정의해야 하기때문에 번거롭다.

이러한 한계를 해결하기 위해 Java 1.5에서 Enum이 도입되었다.

Enum 은 상수를 타입화하고 객체화하여 더 안전하고 확장이 가능한 방식으로 상수를 관리할 수 있게 해주는 도구이다.

열거형이라고 보통 말하는데 열거형이란 말 그대로 사용 가능한 값들을 나열해 놓은 객체를 말한다. Enum을 사용하면 그 안에 명시되어 있는 값들을 미리 정의하고 관리할 수 있게 한다.

한정된 값들만 들어가 있는 특별한 상자라고 생각하면 된다.

Enum 작성법

  • enum 명은 클래스와 같이 첫 문자를 대문자로하고 나머지는 소문자로 구성한다.
  • 관례적으로, 열거 상수는 모두 대문자로 작성한다.
  • 열거 상수가 여러 단어로 구성될 경우, 단어 사이를 밑줄 (_)로 연결한다.
public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

상수들을 열거형으로 선언하고, 각 상수들을 독립된 개체로 관리한다.

IDE에서도 보면 아래와 같이 독립된 Enum 파일로 생성할 수 있는게 보여진다.

primitive 타입이 아닌 reference 타입으로 분류되기 때문에 각 Enum은 메모리의 heap에 저장되고, 고유한 메모리 주소를 가질 수 있다.

→ 상수간에 충돌 없이 독립적으로 관리될 수 있다.

Enum의 객체 지향적 확장

Enum은 클래스처럼 동작하기 때문에 필드와 메서드를 정의할 수 있다.

월~금요일은 기본 출근일이기 때문에 요율 1을 반환하고, 주말은 주말 수당을 붙여 2를 반환하는 Enum을 만들어보자.

public enum Day {
    MONDAY("Weekday", 1),
    TUESDAY("Weekday", 1),
    WEDNESDAY("Weekday", 1),
    THURSDAY("Weekday", 1),
    FRIDAY("Weekday", 1),
    SATURDAY("Weekend", 2),
    SUNDAY("Weekend", 2);

    private final String description; // 요일의 설명 (Weekday, Weekend)
    private final int payRatio;       // 출근(1) 또는 주말 수당(2)

    // Enum 생성자
    Day(String description, int payRatio) {
        this.description = description;
        this.payRatio = payRatio;
    }

    // Getter 메서드
    public String getDescription() {
        return description;
    }

    public int getPayRatio() {
        return payRatio;
    }
    
    public String getWorkType() {
	    return this.payRatio == 1 ? "출근일" : "주말근무";
		}
}

이처럼 Enum을 단순한 상수 정의를 넘어선 객체처럼 활용할 수 있다.

  • 각 상수에 대해 추가적인 데이터를 포함시킬 수 있다. → 데이터를 외부에서 별도로 관리할 필요 없이 Enum 안에서 하나로 캡슐화하여 관리 가능 → 상수와 관련된 데이터를 같은 컨텍스트 안에서 안전하게 유지 가능
  • 필드를 통해 상수 값에 의미를 부여할 수 있어 코드의 가독성이 좋아진다.
    • ex.
      public static final int MONDAY = 1; // 수당을 따로 정의해야 함
      int payRatio = getPayRatio(MONDAY); // 의미가 모호
      
      int payRatio = Day.MONDAY.getPayRatio(); // 가독성이 높음

Enum 기본 메서드

메서드설명예제출력
values()Enum에 정의된 모든 상수값을 배열로 반환Day.values()[MONDAY, TUESDAY, ... SUNDAY]
valueOf(String)Enum 이름과 일치하는 상수를 반환Day.valueOf("MONDAY")MONDAY
name()Enum 상수의 이름을 반환Day.MONDAY.name()MONDAY
ordinal()선언된 순서(0부터 시작)를 반환Day.MONDAY.ordinal()0
compareTo(Enum)Enum 간의 순서를 비교Day.MONDAY.compareTo(Day.FRIDAY)-4

⭐ Enum을 비교할 땐 뭐가 가장 효율적일까?

== 연산자를 사용하는 방법
== 연산자는 Enum 상수 간의 참조 동일성(reference equality)을 검사한다.
Enum 상수는 Java에서 싱글톤으로 관리되기 때문에 항상 동일한 객체를 참조한다.
equals() 를 사용하는 것은 값의 동일성을 검사하는데 Enum에서는 ==와 equals가 동일하게 동작한다. 하지만 Null을 비교할 땐 주의가 필요하기 때문에 참조동일성을 비교하는 ==연산자를 사용하는것이 더 효율적이라고 할 수 있다.

⭐ Flag를 쓸 때 Boolean 대신 Enum을 사용하라

상품 배송 상태를 배송 전과 배송 후를 가를 수 있는 isDelivered 라는 boolean값으로 표현했다고 하자.
그러나 비즈니스 로직이 확장되어  ‘출고 완료’, ‘배송 중’, ‘배송 완료’, ‘배송 취소’ 등 다양한 상태가 추가되면 boolean 값으로는 이러한 상태를 모두 표현하기 어렵다.
이때 Enum을 활용하면 좋다.

// 1. boolean 값으로 표기
public class Order {
    private boolean isDelivered;
}
// 2. enum 으로 표기
public enum ShippingStatus {
    READY_FOR_SHIPMENT, // 출고 준비 중
    SHIPPED,            // 출고 완료
    IN_TRANSIT,         // 배송 중
    DELIVERED,          // 배송 완료
    CANCELED            // 배송 취소
}
public class Order {
    private ShippingStatus shippingStatus;
}

추가 확장에 대해서만 효율적인것이 아니라 명확한 의미 측면에서도 좋다. boolean 타입이었다면 false 상태가 무엇을 의미하는지는 모호하다.
또한 Enum은 타입안정성을 제공한다. 두 매개변수가 모두 boolean일 때, 실수로 순서를 바꿔 전달하는 위험을 줄일 수 있다. Enum은 매개변수 간의 혼동을 방지해 안전한 코드를 작성하는 데 도움을 줄 수 있다.


결론
여러 상태를 다뤄야 하거나 매개변수 간 혼동을 방지해야 하는 상황에서 Enum은 Boolean보다 훨씬 안전하고 효율적인 선택이다.

profile
어제의 나보단 나은 오늘의 내가 되기를

0개의 댓글