아이템 35. ordinal 메소드 대신 인스턴스 필드를 사용하라. - ksw6169/effective-java GitHub Wiki

ordinal 메소드

  • 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal 이라는 메소드를 제공한다. (1, 2, ... 순으로 각 상수에 숫자를 부여한다.)
  • 따라서 열거 타입 상수와 연결된 정수값이 필요하면 ordinal 메소드를 이용하고 싶을 수 있다.
public enum Ensemble {

    SOLO, DUET, TRIO, QUARTET, QUINTET,
    SEXTET, SEPTET, OCTET, NONET, DECTET;

    public int numberOfMusicians() {
        return ordinal() + 1;
    }
}
  • 하지만 ordinal을 직접 사용해서는 안된다. 치명적인 단점이 있기 때문이다.

ordinal을 직접 사용해서는 안되는 이유

1. 상수 선언 순서를 바꾸는 순간 오동작할 수 있다.

  • 위 예제의 Ensemble 열거 타입에서 상수 선언 순서를 바꾸는 순간 ordinal을 사용한 numberOfMusicians 메소드가 오동작할 수 있다.

2. 이미 사용 중인 정수와 값이 같은 상수는 추가할 방법이 없다.

  • 예를 들어 정수 4에 해당하는 상수가 이미 있는 경우 같은 값을 가지는 상수를 추가할 방법이 없다.
  • 또한 첫 번째 상수부터 연속적으로 값을 부여하므로 값을 중간에 비워둘 수도 없다.

해결책

이를 해결하는 방법은 열거 타입 상수에 연결된 값은 ordinal 메소드로 얻지 말고 인스턴스 필드에 저장하는 것이다.

public enum Ensemble {

    SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
    SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8),
    NONET(9), DECTET(10), TRIPLE_QUARTET(12);

    private final int numberOfMusicians;

    Ensemble(int numberOfMusicians) {
        this.numberOfMusicians = numberOfMusicians;
    }

    public int getNumberOfMusicians() {
        return numberOfMusicians;
    }
}

참고 사항

Enum의 API 문서를 보면 ordinal에 대해 이렇게 쓰여 있다. "대부분의 프로그래머는 이 메소드를 쓸 일이 없다. 이 메소드는 EnumSet과 EnumMap 같이 열거 타입 기반의 범용 자료구조에 쓸 목적으로 설계되었다." 따라서 이런 용도가 아니라면 ordinal은 절대 사용해선 안된다.

참고 자료

  • Effective Java 3/E