Преобразовать из порядкового номера перечисления в тип перечисления - PullRequest
281 голосов
/ 04 марта 2009

У меня есть тип enum ReportTypeEnum, который передается между методами во всех моих классах, но затем мне нужно передать это по URL, чтобы я использовал метод ordinal для получения значения int. После того, как я получу его на другой моей странице JSP, мне нужно преобразовать его обратно в ReportTypeEnum, чтобы я мог продолжить передавать его.

Как я могу преобразовать порядковый номер в ReportTypeEnum?

Использование Java 6 SE.

Ответы [ 11 ]

575 голосов
/ 04 марта 2009

Чтобы преобразовать порядковый номер в его представление enum, вы можете сделать это:

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

Пожалуйста, обратите внимание на границы массива.

Обратите внимание, что каждый вызов values() возвращает новый клонированный массив, который может отрицательно повлиять на производительность. Вы можете кэшировать массив, если он будет часто вызываться.

Пример кода для кеширования values().


Этот ответ был отредактирован с учетом отзывов, содержащихся в комментариях

136 голосов
/ 04 марта 2009

Это почти наверняка плохая идея . Конечно, если порядковый номер де-факто сохранен (например, потому что кто-то добавил в закладки URL) - это означает, что вы всегда должны сохранять порядок enum в будущем, что может быть неочевидно для сопровождающих кода вниз линия.

Почему бы не кодировать enum, используя myEnumValue.name() (и вместо этого декодировать с помощью ReportTypeEnum.valueOf(s))?

87 голосов
/ 09 октября 2013

Если я собираюсь использовать values() много:

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

Тем временем, где.java:

Suit suit = Suit.values[ordinal];

Следите за границами вашего массива.

7 голосов
/ 02 января 2014

Я согласен с большинством людей, что использование порядкового номера, вероятно, плохая идея. Я обычно решаю эту проблему, предоставляя enum приватный конструктор, который может принимать, например, значение DB, а затем создавать статическую функцию fromDbValue, аналогичную той, что была в ответе Яна.

public 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;
    }

}

Теперь вы можете изменить порядок, не изменяя поиск, и наоборот.

7 голосов
/ 09 января 2011

Вы можете использовать статическую таблицу поиска:

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);
  }
}
4 голосов
/ 01 апреля 2015

Это то, что я использую. Я не претендую на то, что он гораздо менее «эффективен», чем простые решения, описанные выше. Что он делает, так это предоставляет гораздо более четкое сообщение об исключении, чем «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);
}
1 голос
/ 28 июня 2018

Это то, что я делаю на Android с Proguard:

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

0 голосов
/ 23 мая 2019

Вы можете определить простой метод, например:

public enum Alphabet{
    A,B,C,D;

    public static Alphabet get(int index){
        return Alphabet.values()[index];
    }
}

И используйте это как:

System.out.println(Alphabet.get(2));
0 голосов
/ 21 января 2019

Таким образом, один из способов - сделать ExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal];, который работает и его легко, однако, как упоминалось ранее, ExampleEnum.values() возвращает новый клонированный массив для каждого вызова. Это может быть излишне дорого. Мы можем решить это путем кэширования массива примерно так: ExampleEnum[] values = values(). Также «опасно» разрешать изменение нашего кэшированного массива. Кто-то может написать ExampleEnum.values[0] = ExampleEnum.type2; Так что я бы сделал его закрытым с помощью метода доступа, который не выполняет дополнительное копирование.

private enum ExampleEnum{
    type0, type1, type2, type3;
    private static final ExampleEnum[] values = values();
    public static ExampleEnum value(int ord) {
        return values[ord];
    }
}

Вы бы использовали ExampleEnum.value(ordinal), чтобы получить значение перечисления, связанное с ordinal

0 голосов
/ 02 марта 2017
public enum Suit implements java.io.Serializable, Comparable<Suit>{
  spades, hearts, diamonds, clubs;
  private static final Suit [] lookup  = Suit.values();
  public Suit fromOrdinal(int ordinal) {
    if(ordinal< 1 || ordinal> 3) return null;
    return lookup[value-1];
  }
}

тестовый класс

public class MainTest {
    public static void main(String[] args) {
        Suit d3 = Suit.diamonds;
        Suit d3Test = Suit.fromOrdinal(2);
        if(d3.equals(d3Test)){
            System.out.println("Susses");
        }else System.out.println("Fails");
    }
}

Я ценю, что вы делитесь с нами, если у вас есть более эффективный код, Мой список огромен и постоянно вызывается тысячи раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...