본문 바로가기
Language/Java

[Java] Enum 활용하기

by 1000zoo 2023. 10. 24.

Enum

특정 값들만을 가질 수 있는 타입을 정의할 때 사용된다. 예를 들어, HTTP code의 경우, 각 코드들과 의미가 일대일로 대응되고, 종류가 정해져있으므로, 이를 enum으로 정의할 수 있다. 이렇게 해 두면, 이 타입의 변수는 정의된 값들 중 하나만을 가질 수 있게 되어 코드를 더 안전하게 만들 수 있다. 또한, 자체적으로 클래스이므로, 메소드나 필드를 가질 수 있어 상수를 정의할 때도 사용할 수 있다.

ex

// enum 정의
public enum Status {  
    OK(200, "요청 성공"),  
    MULTIPLE_CHOICE(300, "하나 이상의 응답 가능"),  
    BAD_REQUEST(400, "서버가 요청을 이해할 수 없음"),  
    NOT_FOUND(404, "요청받은 리소스를 찾을 수 없음");  

    private final int code;  
    private final String detail;  

    Status(int code, String detail) {  
        this.code = code;  
        this.detail = detail;  
    }  

    public int getCode() {  
        return code;  
    }  

    public String getDetail() {  
        return detail;  
    }  
}
  • 맨 위에 enum 값들이 정의된다.
  • 괄호 안의 값은, enum값에 해당되는 필드 변수들이다.
  • class와 마찬가지로, 생성자(같은 형태) 및 getter를 가질 수 있다.
    • 생성자의 modifier는 필요없다.

위와같이 정의해 두면, 아래와 같이 사용할 수 있다.

Status ok = Status.OK; // enum값 할당
System.out.println("ok = " + ok); // ok = OK
System.out.println("ok.getCode() = " + ok.getCode()); // ok.getCode() = 200
System.out.println("ok.getDetail() = " + ok.getDetail()); // ok.getDetails() = 요청 성공

기본 메소드

values()

enum의 모든 요소를 포함하는 배열을 반환

ex

Status[] statuses = Status.values();  

for (Status status : statuses) {  
    System.out.println("status = " + status);  
}
//results
status = OK
status = MULTIPLE_CHOICE
status = BAD_REQUEST
status = NOT_FOUND

valueOf(String name)

문자열에 해당하는 enum 요소를 반환한다. 정확하게 일치하지 않을 경우, IllegalArgumentException이 발생한다.

ex

Status ok = Status.valueOf("OK");
System.out.println("ok = " + ok); // ok = OK

Status badRequest = Status.valueOf("bad"); // IllegalArgumentException 발생

ordinal()

enum 요소의 위치를 반환한다. 이 위치는 enum에서 선언된 순서에 따라 결정된다.

ex

Status[] statuses = Status.values();  

for (Status status : statuses) {  
    System.out.println(status + " => " + status.ordinal());  
}
//results
OK => 0
MULTIPLE_CHOICE => 1
BAD_REQUEST => 2
NOT_FOUND => 3

name()

enum 요소의 이름을 문자열로 반환한다.

ex

Status[] statuses = Status.values();  

for (Status status : statuses) {  
    System.out.println(status + " => " + status.name());  
}
//results
OK => OK
MULTIPLE_CHOICE => MULTIPLE_CHOICE
BAD_REQUEST => BAD_REQUEST
NOT_FOUND => NOT_FOUND

toString()

name()과 마찬가지로, enum 요소의 이름을 문자열로 반환한다. 차이점은 toString()은 오버라이드 될 수 있다는 것이다.

ex

//Status.java에 추가
@Override  
public String toString() {  
    return name() + "{" +  
            "code=" + code +  
            ", detail='" + detail + '\'' +  
            '}';  
}
//results
status = OK{code=200, detail='요청 성공'}
status = MULTIPLE_CHOICE{code=300, detail='하나 이상의 응답 가능'}
status = BAD_REQUEST{code=400, detail='서버가 요청을 이해할 수 없음'}
status = NOT_FOUND{code=404, detail='요청받은 리소스를 찾을 수 없음'}

compareTo(E e)

현재 enum 요소와 다른 enum 요소를 비교한다. 비교는 ordinal 값에 기반한다.

Status ok = Status.OK;  
Status notFound = Status.NOT_FOUND;  

System.out.println(ok.compareTo(notFound)); // -3

응용

필드값으로 enum 찾기

loop 이용

enum 내부의 static 메소드를 만들어, values() 메소드로 모두 순회하면서 찾으면 된다.

ex

public static Status findByCode(int code) {  
    return Arrays.stream(values()).filter(o -> o.getCode() == code)  
            .findFirst()  
            .orElse(Status.NOT_FOUND);  
}

Map 이용

필드 변수로 맵을 사전에 만들어 둔다.

ex

private static final Map<Integer, Status> CODE_MAP = Collections.unmodifiableMap(  
        Arrays.stream(values()).collect(Collectors.toMap(Status::getCode, o -> o))  
);

public static Status findByCodeMap(int code) {  
    if (!CODE_MAP.containsKey(code)) {  
        return null;  
    }  
    return CODE_MAP.get(code);  
}