2015-07-04 3 views
1

Мой код содержит несколько перечислений, как показано ниже. В основном это помогает использовать перечисление через integer вместо значения enum. Возможно ли применить такую ​​оптимизацию, как наследование или что-то подобное, чтобы все могли иметь поведение, как показано ниже.Оптимизация java enum

public enum DeliveryMethods { 

    STANDARD_DOMESTIC(1), STANDARD_INTERNATIONAL(2), EXPRESS_DOMESTIC(3), EXPRESS_INTERNATIONAL(4); 

    private final int code; 

    private DeliveryMethods(int code) { 
     this.code = code; 
    } 

    public int getCode() { 
     return code; 
    } 

    private static final HashMap<Integer, DeliveryMethods> valueMap = new HashMap<>(2); 

    static { 
     for (DeliveryMethods type : DeliveryMethods.values()) { 
      valueMap.put(type.code, type); 
     } 
    } 

    public static DeliveryMethods getValue(int code) { 
     return valueMap.get(code); 
    } 
} 
+1

Почему вы хотите использовать его с помощью целого числа? Это наносит ущерб некоторым преимуществам использования перечисления в первую очередь. –

+0

Существует ряд причин, которые могут потребоваться, например, декодирование значений из двоичного файла или БД. –

+0

Какая «оптимизация» вы здесь? Что неудовлетворительно в отношении вашего нынешнего подхода? –

ответ

4

Здесь является примером того, как вы можете делегировать в другой класс:

public interface Keyed<K> { 
    /** 
    * returns the key of the enum 
    */ 
    K getKey(); 
} 

public class KeyEnumMapping<K, E extends Enum<?> & Keyed<K>> { 
    private Map<K, E> map = new HashMap<>(); 

    public KeyEnumMapping(Class<E> clazz) { 
     E[] enumConstants = clazz.getEnumConstants(); 
     for (E e : enumConstants) { 
      map.put(e.getKey(), e); 
     } 
    } 

    public E get(K key) { 
     return map.get(key); 
    } 
} 

public enum Example implements Keyed<Integer> { 
    A(1), 
    B(3), 
    C(7); 

    private static final KeyEnumMapping<Integer, Example> MAPPING = new KeyEnumMapping<>(Example.class); 
    private Integer value; 

    Example(Integer value) { 
     this.value = value; 
    } 

    @Override 
    public Integer getKey() { 
     return value; 
    } 

    public static Example getByValue(Integer value) { 
     return MAPPING.get(value); 
    } 

    public static void main(String[] args) { 
     System.out.println(Example.getByValue(3)); 
    } 
} 

Вы также можете избежать внедрения шпоночный интерфейс и просто передать Function<E, K> в KeyEnumMapping конструктора, который превратит его в перечисление ключа:

public class KeyEnumMapping<K, E extends Enum<?>> { 
    private Map<K, E> map = new HashMap<>(); 

    public KeyEnumMapping(Class<E> clazz, Function<E, K> keyExtractor) { 
     E[] enumConstants = clazz.getEnumConstants(); 
     for (E e : enumConstants) { 
      map.put(keyExtractor.apply(e), e); 
     } 
    } 

    public E get(K key) { 
     return map.get(key); 
    } 
} 

public enum Example { 
    A(1), 
    B(3), 
    C(7); 

    private static final KeyEnumMapping<Integer, Example> MAPPING = 
     new KeyEnumMapping<>(Example.class, Example::getValue); 
    private Integer value; 

    Example(Integer value) { 
     this.value = value; 
    } 

    public Integer getValue() { 
     return value; 
    } 

    public static Example getByValue(Integer value) { 
     return MAPPING.get(value); 
    } 

    public static void main(String[] args) { 
     System.out.println(Example.getByValue(3)); 
    } 
} 
+0

Спасибо, сэр. Идеальное решение. Это также поможет мне узнать о функциональном интерфейсе Java 8 и операторе двойной толстой кишки. –

+0

@DSingh '::' на самом деле не является оператором; 'Example :: getValue' является [ссылкой на метод] (https://docs.oracle.ком/JavaSE/учебник/Java/javaOO/methodreferences.html). – Jesper

+0

@Jesper Я на самом деле googled «двойной двоеточие в java», и результаты заявили его как оператора. Спасибо, что указали это. Я думаю, что большинство людей, которые не читают документацию на Java 8, будут ссылаться на нее как на оператора. Но я обновил себя. Спасибо. –

0

Вы можете использовать метод getOrdinal() для Enum вместо того, чтобы поддерживать «код» самостоятельно.

http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#ordinal()

Даже если вы поддерживаете «код» приписывать не надо поддерживать «valueMap». Вместо этого вы можете использовать метод «values ​​()» Enum и перебрать все перечисления.

+0

Это сломается, если вы измените порядок значений перечисления или добавьте некоторое значение в середине. –

+0

getOrdinal() означает целочисленное значение по умолчанию, начинающееся с 0 и не зависящее от значения перечисления. getOrdinal() будет терпеть неудачу с значениями DB, если в будущей позиции изменения значения перечисления. –

+0

@kpavlov да! точно –

0

Там нет необходимости Hashmap если пока это не necessary.It уж лучше не идти с switch-case для enum значений

я написал, чтобы получить перечисление из Integer, а также строку

public enum DeliveryMethods { 

    STANDARD_DOMESTIC(1), STANDARD_INTERNATIONAL(2), EXPRESS_DOMESTIC(3), EXPRESS_INTERNATIONAL(4); 

    private final int code; 

    private DeliveryMethods(int code) { 
     this.code = code; 
    } 

    public int getCode() { 
     return code; 
    } 

    public static DeliveryMethods fromString(String code) { 
     if (code.matches("[1-4]")) { 
      return fromInteger(Integer.valueOf(code)); 
     } 
     throw new RuntimeException("No values for code " + code); 
    } 

    public static DeliveryMethods fromInteger(int code) { 
     switch (code) { 
      case 1: 
       return STANDARD_DOMESTIC; 
      case 2: 
       return STANDARD_INTERNATIONAL; 
      case 3: 
       return EXPRESS_DOMESTIC; 
      case 4: 
       return EXPRESS_INTERNATIONAL; 
     } 
     throw new RuntimeException("No values for code " + code); 
    } 

    public static DeliveryMethods fromIntegerType2(int code) { 
     for (DeliveryMethods d : DeliveryMethods.values()) { 
      if (d.getCode() == code) { 
       return d; 
      } 
     } 
     throw new RuntimeException("No values for code " + code); 
    } 
} 
+0

Один из недостатков этого метода, когда вводятся новые значения enum, код необходимо изменить. Так что это не так, чтобы расширяться –

+0

Да, вы добавляете новое перечисление, значит, вы также должны добавить новый случай. Но это оптимизированный подход, как вы просили – Madhan

+1

@DevBlanked. Я добавил новый подход. Думаю, этого хватит – Madhan