ENUM 이란

보통 프로젝트내에서 자주 사용되는 코드를 모아 ENUM을 만들곤 합니다.
여러 개발자들이 오타를 내거나 조금씩 다른 코드를 작성할 가능성이 있으므로 이러한 코드들을 하나의 ENUM클래스에 모아 정의합니다.
이러한 ENUM은 명시된 타입만을 가지므로 타입에 안정성을 가집니다.
또한 자주 사용하면서 읽기 쉬운 키워드로 되어 있어 가독성이 좋아집니다.

ENUM은 컴파일시 정의되고 정적 메모리에 할당됩니다.
그러므로 new 를 붙여 생성할 필요가 없습니다.
런타임시 변하지 않으므로 메모리에 한 구역만 사용합니다.
따라서 ENUM은 싱글톤이되어 인스턴스를 재사용하게 됩니다.

// 기본적인 ENUM 생성 방법
public enum Day {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}


확장된 ENUM

ENUM은 보통 확장된 ENUM의 형태로 사용됩니다.

public enum Day {
    MONDAY("월요일"),
    TUESDAY("화요일"),
    WEDNESDAY("수요일"),
    THURSDAY("목요일"),
    FRIDAY("금요일"),
    SATURDAY("토요일"),
    SUNDAY("일요일"),
    UNKNOWN("N/A");

    private final String koreanName;

    Day(String koreanName) {
        this.koreanName = koreanName;
    }

    public String getKoreanName() {
        return koreanName;
    }
}

사용 예시

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

    System.out.println(day); // MONDAY
    System.out.println(day.getKoreanName()); // 월요일

    for (Day d : Day.values()) {
        System.out.println(d + ": " + d.getKoreanName());
    }
}

values()

values() 메서드는 Java에서 모든 enum에 내장되어 있는 특수한 메서드입니다. 이를 따로 정의할 필요가 없으며, 컴파일러가 자동으로 생성합니다.
values()는 현재 enum에 정의된 모든 열거 상수를 배열로 반환합니다.

예를들어 아래와 같이 사용할 수 있습니다

for (Day day : Day.values()) {
    System.out.println(day.getKoreanName());
}

>> 월요일
   화요일
   수요일
   목요일
   금요일
   토요일
   일요일

valueOf()

문자열로 enum 상수를 검색하여 반환
주어진 문자열이 상수 이름과 정확히 일치해야 합니다(대소문자 구분)

예를들어 아래와 같이 사용될 수 있습니다

public static void main(String[] args) {
    Day day1 = Day.valueOf("월요일");
    System.out.println("Day1: " + day1 + ", KoreanName: " + day1.getKoreanName());

    try {
        Day day2 = Day.valueOf("월 요일");
    } catch (IllegalArgumentException e) {
        System.out.println("Exception: " + e.getMessage());
    }
}
    
>> Day1: MONDAY, Key: 월요일
   Exception: No enum constant Day.invalidValue

안전하게 상수 가져오기

// 첫번째 방법(함수형 프로그래밍 스타일)
public static Day find(String name) {
    return Arrays.stream(values())
            .filter(e -> e.koreanName.equals(name))
            .findAny()
            .orElse(UNKNOWN);
}

// 두번째 방법
public static Day safeValueOf(String name) {
    for (Day day : Day.values()) {
        if (day.getKoreanName().equals(name)) {
            return day;
        }
    }
    return Day.UNKNOWN;
}

final

final 필드로 ENUM을 만드는 이유는 아래와 같습니다.

  • 불변하게 만들어서 상수의 안정성을 도모
  • 스레드 안전을 보장
  • 컴파일러가 최적화를 함

@Getter와 함께 사용한 경우

public enum Param {
    CONTENT("content", true),
    PAGEABLE("pageable", true),
    SEARCH_PARAM("searchParam", true),
    MESSAGE("message", true),
    SUCCESS_FLAG("succes", true),
    FAIL_FLAG("fail", false),
    FILE_NAME("fileName", true),
    HEADERS("headers", true),
    CELLS("cells", true),
    ROWS("rows", true),
    WORKBOOK("workbook", true);

    @Getter
    private final String value;
    @Getter
    private final boolean bool;

    Param(String value, Boolean bool) {
        this.value = value;
        this.bool = bool;
    }
}


인터페이스

인터페이스를 통해서도 상수를 만들 수 있습니다.

public interface MessageProvider {
    String getMessage();
}
public enum Status implements MessageProvider {
    SUCCESS {
        @Override
        public String getMessage() {
            return "Operation was successful.";
        }
    },
    FAILURE {
        @Override
        public String getMessage() {
            return "Operation failed.";
        }
    };
}
public class Main {
    public static void main(String[] args) {
        Status status = Status.SUCCESS;
        System.out.println(status.getMessage()); // "Operation was successful."

        status = Status.FAILURE;
        System.out.println(status.getMessage()); // "Operation failed."
    }
}
  • 인터페이스 확장
public interface Volume {
    int MAX_VOLUME = 10;	
    int MIN_VOLUME = 0;
}
public interface AdvancedVolume extends Volume {
    int DEFAULT_VOLUME = 5;
}

인터페이스를 통해 정의된 상수는 public static final이 됩니다.
public static final는 불변성만을 가질뿐 타입에 제한이 없습니다.
아래처럼 여러가지 타입을 섞어서 만들수가 있기 때문에 안정성이 떨어집니다.

public interface ExampleInterface {
    int NUMBER_CONSTANT = 1;
    String STRING_CONSTANT = "Hello";
    boolean BOOLEAN_CONSTANT = true;
}

또한 이러한 인터페이스를 여러 클래스에서 구현할때 네임 스페이스가 오염될 수 있습니다.

public interface Vehicle {
    int MAX_SPEED = 120;
    int MIN_SPEED = 0;
    String VEHICLE_TYPE = "Car";
    boolean HAS_WHEELS = true;
}

public class Car implements Vehicle {
    
}

public class Bicycle implements Vehicle {
   
}

여기서 CarBicycleVehicle의 모든 상수가 필요 없음에도 클래스 내에 이러한 상수들을 가지게 됩니다.
이로 인해 자동완성이 혼잡해지거나 실수를 유발할 수 있습니다.

따라서 ENUM을 사용한다면 확장된 ENUM클래스를 만들어 이용하는것이 좋습니다.

profile
작은것부터

0개의 댓글

Powered by GraphCDN, the GraphQL CDN