[java] 열거 형 서수에서 열거 형으로 변환

나는 ReportTypeEnum모든 클래스의 메소드간에 전달 되는 열거 형 을 가지고 있지만 URL에 이것을 전달해야 서수 메소드를 사용하여 int 값을 얻습니다. 다른 JSP 페이지에서 가져온 후에 ReportTypeEnum는 계속 전달할 수 있도록 다시 변환해야 합니다.

서수를 어떻게로 변환 할 수 ReportTypeEnum있습니까?

Java 6 SE 사용



답변

서수를 열거 형 represantation으로 변환하려면 다음을 수행하십시오.

ReportTypeEnum value = ReportTypeEnum.values()[ordinal];

배열 범위를 확인하십시오.

호출 할 때마다 values()새로 복제 된 배열 을 반환하므로 성능에 부정적인 영향을 줄 수 있습니다. 배열이 자주 호출되는 경우 배열을 캐시 할 수 있습니다.

캐시하는 방법에 대한 코드 예제values() .


이 답변은 댓글 안에 제공된 피드백을 포함하도록 편집되었습니다


답변

이것은 거의 확실히 나쁜 생각 입니다. 물론 서 수가 사실상 유지되지 않는 경우 (예 : 누군가가 URL을 북마크에 추가했기 때문에) enum이는 향후 순서를 항상 유지해야한다는 것을 의미합니다 . 이는 코드 관리자에게 명확하지 않을 수 있습니다.

대신 인코딩을 enum사용하고 myEnumValue.name()(를 통해 디코딩 ReportTypeEnum.valueOf(s)) 왜 안 됩니까?


답변

values()많이 사용할 예정이라면 :

enum Suit {
   Hearts, Diamonds, Spades, Clubs;
   public static final Suit values[] = values();
}

한편 where.java :

Suit suit = Suit.values[ordinal];

배열 경계를 염두에 두십시오.


답변

나는 서수를 사용하는 것이 아마도 나쁜 생각이라는 대부분의 사람들에게 동의합니다. 나는 일반적으로 열거 형에 DB 값을 취할 수있는 개인 생성자를 제공하여 fromDbValueJan의 답변과 비슷한 정적 함수 를 생성 하여이 문제를 해결합니다 .

public enum ReportTypeEnum {
    R1(1),
    R2(2),
    R3(3),
    R4(4),
    R5(5),
    R6(6),
    R7(7),
    R8(8);

    private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);
    private static Map<Integer, ReportTypeEnum> lookup;
    private Integer dbValue;

    private ReportTypeEnum(Integer dbValue) {
        this.dbValue = dbValue;
    }


    static {
        try {
            ReportTypeEnum[] vals = ReportTypeEnum.values();
            lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);

            for (ReportTypeEnum  rpt: vals)
                lookup.put(rpt.getDbValue(), rpt);
         }
         catch (Exception e) {
             // Careful, if any exception is thrown out of a static block, the class
             // won't be initialized
             log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
         }
    }

    public static ReportTypeEnum fromDbValue(Integer dbValue) {
        return lookup.get(dbValue);
    }

    public Integer getDbValue() {
        return this.dbValue;
    }

}

이제 조회를 변경하지 않고 순서를 변경할 수 있으며 그 반대도 마찬가지입니다.


답변

당신은 할 수 정적 조회 테이블을 사용합니다 :

public enum Suit {
  spades, hearts, diamonds, clubs;

  private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();

  static{
    int ordinal = 0;
    for (Suit suit : EnumSet.allOf(Suit.class)) {
      lookup.put(ordinal, suit);
      ordinal+= 1;
    }
  }

  public Suit fromOrdinal(int ordinal) {
    return lookup.get(ordinal);
  }
}


답변

이것이 내가 사용하는 것입니다. 위의 간단한 솔루션보다 훨씬 덜 “효율적”이라고 주장하지 않습니다. 위의 솔루션에서 유효하지 않은 서수 값을 사용하는 경우 “ArrayIndexOutOfBounds”보다 훨씬 명확한 예외 메시지를 제공합니다.

EnumSet javadoc이 반복자가 요소를 자연 순서로 반환하도록 지정한다는 사실을 이용합니다. 정확하지 않은 주장이 있습니다.

JUnit4 테스트는 사용 방법을 보여줍니다.

 /**
 * convert ordinal to Enum
 * @param clzz may not be null
 * @param ordinal
 * @return e with e.ordinal( ) == ordinal
 * @throws IllegalArgumentException if ordinal out of range
 */
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
    EnumSet<E> set = EnumSet.allOf(clzz);
    if (ordinal < set.size()) {
        Iterator<E> iter = set.iterator();
        for (int i = 0; i < ordinal; i++) {
            iter.next();
        }
        E rval = iter.next();
        assert(rval.ordinal() == ordinal);
        return rval;
    }
    throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}

@Test
public void lookupTest( ) {
    java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
    System.out.println(tu);
}


답변

이것이 Proguard를 사용하여 Android에서 수행하는 작업입니다.

public enum SomeStatus {
    UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order

    private static SomeStatus[] values = null;
    public static SomeStatus fromInteger(int i) {
        if(SomeStatus.values == null) {
            SomeStatus.values = SomeStatus.values();
        }
        if (i < 0) return SomeStatus.values[0];
        if (i >= SomeStatus.values.length) return SomeStatus.values[0];
        return SomeStatus.values[i];
    }
}

짧고 Proguard에서 예외가 발생할 염려가 없습니다.