Conveniently map between enum and int / String

前端 未结 18 1715
陌清茗
陌清茗 2020-11-28 01:07

When working with variables/parameters that can only take a finite number of values, I try to always use Java\'s enum, as in

public enum BonusT         


        
相关标签:
18条回答
  • 2020-11-28 01:26

    Really great question :-) I used solution similar to Mr.Ferguson`s sometime ago. Our decompiled enum looks like this:

    final class BonusType extends Enum
    {
    
        private BonusType(String s, int i, int id)
        {
            super(s, i);
            this.id = id;
        }
    
        public static BonusType[] values()
        {
            BonusType abonustype[];
            int i;
            BonusType abonustype1[];
            System.arraycopy(abonustype = ENUM$VALUES, 0, abonustype1 = new BonusType[i = abonustype.length], 0, i);
            return abonustype1;
        }
    
        public static BonusType valueOf(String s)
        {
            return (BonusType)Enum.valueOf(BonusType, s);
        }
    
        public static final BonusType MONTHLY;
        public static final BonusType YEARLY;
        public static final BonusType ONE_OFF;
        public final int id;
        private static final BonusType ENUM$VALUES[];
    
        static 
        {
            MONTHLY = new BonusType("MONTHLY", 0, 1);
            YEARLY = new BonusType("YEARLY", 1, 2);
            ONE_OFF = new BonusType("ONE_OFF", 2, 3);
            ENUM$VALUES = (new BonusType[] {
                MONTHLY, YEARLY, ONE_OFF
            });
        }
    }
    

    Seeing this is apparent why ordinal() is unstable. It is the i in super(s, i);. I'm also pessimistic that you can think of a more elegant solution than these you already enumerated. After all enums are classes as any final classes.

    0 讨论(0)
  • 2020-11-28 01:26

    I needed something different because I wanted to use a generic approach. I'm reading the enum to and from byte arrays. This is where I come up with:

    public interface EnumConverter {
        public Number convert();
    }
    
    
    
    public class ByteArrayConverter {
    @SuppressWarnings("unchecked")
    public static Enum<?> convertToEnum(byte[] values, Class<?> fieldType, NumberSystem numberSystem) throws InvalidDataException {
        if (values == null || values.length == 0) {
            final String message = "The values parameter must contain the value";
            throw new IllegalArgumentException(message);
        }
    
        if (!dtoFieldType.isEnum()) {
            final String message = "dtoFieldType must be an Enum.";
            throw new IllegalArgumentException(message);
        }
    
        if (!EnumConverter.class.isAssignableFrom(fieldType)) {
            final String message = "fieldType must implement the EnumConverter interface.";
            throw new IllegalArgumentException(message);
        }
    
        Enum<?> result = null;
        Integer enumValue = (Integer) convertToType(values, Integer.class, numberSystem); // Our enum's use Integer or Byte for the value field.
    
        for (Object enumConstant : fieldType.getEnumConstants()) {
            Number ev = ((EnumConverter) enumConstant).convert();
    
            if (enumValue.equals(ev)) {
                result = (Enum<?>) enumConstant;
                break;
            }
        }
    
        if (result == null) {
            throw new EnumConstantNotPresentException((Class<? extends Enum>) fieldType, enumValue.toString());
        }
    
        return result;
    }
    
    public static byte[] convertEnumToBytes(Enum<?> value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
        if (!(value instanceof EnumConverter)) {
            final String message = "dtoFieldType must implement the EnumConverter interface.";
            throw new IllegalArgumentException(message);
        }
    
        Number enumValue = ((EnumConverter) value).convert();
        byte[] result = convertToBytes(enumValue, requiredLength, numberSystem);
        return result;
    }
    
    public static Object convertToType(byte[] values, Class<?> type, NumberSystem numberSystem) throws InvalidDataException {
        // some logic to convert the byte array supplied by the values param to an Object.
    }
    
    public static byte[] convertToBytes(Object value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
        // some logic to convert the Object supplied by the'value' param to a byte array.
    }
    }
    

    Example of enum's:

    public enum EnumIntegerMock implements EnumConverter {
        VALUE0(0), VALUE1(1), VALUE2(2);
    
        private final int value;
    
        private EnumIntegerMock(int value) {
            this.value = value;
        }
    
    public Integer convert() {
        return value;
    }
    

    }

    public enum EnumByteMock implements EnumConverter {
        VALUE0(0), VALUE1(1), VALUE2(2);
    
        private final byte value;
    
        private EnumByteMock(int value) {
            this.value = (byte) value;
        }
    
        public Byte convert() {
            return value;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 01:30

    Just because the accepted answer is not self contained:

    Support code:

    public interface EnumWithCode<E extends Enum<E> & EnumWithCode<E>> {
    
        public Integer getCode();
    
        E fromCode(Integer code);
    }
    
    
    public class EnumWithCodeMap<V extends Enum<V> & EnumWithCode<V>> {
    
        private final HashMap<Integer, V> _map = new HashMap<Integer, V>();
    
        public EnumWithCodeMap(Class<V> valueType) {
            for( V v : valueType.getEnumConstants() )
                _map.put(v.getCode(), v);
        }
    
        public V get(Integer num) {
            return _map.get(num);
        }
    }
    

    Example of use:

    public enum State implements EnumWithCode<State> {
        NOT_STARTED(0), STARTED(1), ENDED(2);
    
        private static final EnumWithCodeMap<State> map = new EnumWithCodeMap<State>(
                State.class);
    
        private final int code;
    
        private State(int code) {
            this.code = code;
        }
    
        @Override
        public Integer getCode() {
            return code;
        }
    
        @Override
        public State fromCode(Integer code) {
            return map.get(code);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-28 01:31

    Use an interface to show it who's boss.

    public interface SleskeEnum {
        int id();
    
        SleskeEnum[] getValues();
    
    }
    
    public enum BonusType implements SleskeEnum {
    
    
      MONTHLY(1), YEARLY(2), ONE_OFF(3);
    
      public final int id;
    
      BonusType(int id) {
        this.id = id;
      }
    
      public SleskeEnum[] getValues() {
        return values();
      }
    
      public int id() { return id; }
    
    
    }
    
    public class Utils {
    
      public static SleskeEnum getById(SleskeEnum type, int id) {
          for(SleskeEnum t : type.getValues())
              if(t.id() == id) return t;
          throw new IllegalArgumentException("BonusType does not accept id " + id);
      }
    
      public static void main(String[] args) {
    
          BonusType shouldBeMonthly = (BonusType)getById(BonusType.MONTHLY,1);
          System.out.println(shouldBeMonthly == BonusType.MONTHLY);
    
          BonusType shouldBeMonthly2 = (BonusType)getById(BonusType.MONTHLY,1);
          System.out.println(shouldBeMonthly2 == BonusType.YEARLY);
    
          BonusType shouldBeYearly = (BonusType)getById(BonusType.MONTHLY,2);
          System.out.println(shouldBeYearly  == BonusType.YEARLY);
    
          BonusType shouldBeOneOff = (BonusType)getById(BonusType.MONTHLY,3);
          System.out.println(shouldBeOneOff == BonusType.ONE_OFF);
    
          BonusType shouldException = (BonusType)getById(BonusType.MONTHLY,4);
      }
    }
    

    And the result:

    C:\Documents and Settings\user\My Documents>java Utils
    true
    false
    true
    true
    Exception in thread "main" java.lang.IllegalArgumentException: BonusType does not accept id 4
            at Utils.getById(Utils.java:6)
            at Utils.main(Utils.java:23)
    
    C:\Documents and Settings\user\My Documents>
    
    0 讨论(0)
  • 2020-11-28 01:33

    Seems the answer(s) to this question are outdated with the release of Java 8.

    1. Don't use ordinal as ordinal is unstable if persisted outside the JVM such as a database.
    2. It is relatively easy to create a static map with the key values.

    public enum AccessLevel {
      PRIVATE("private", 0),
      PUBLIC("public", 1),
      DEFAULT("default", 2);
    
      AccessLevel(final String name, final int value) {
        this.name = name;
        this.value = value;
      }
    
      private final String name;
      private final int value;
    
      public String getName() {
        return name;
      }
    
      public int getValue() {
        return value;
      }
    
      static final Map<String, AccessLevel> names = Arrays.stream(AccessLevel.values())
          .collect(Collectors.toMap(AccessLevel::getName, Function.identity()));
      static final Map<Integer, AccessLevel> values = Arrays.stream(AccessLevel.values())
          .collect(Collectors.toMap(AccessLevel::getValue, Function.identity()));
    
      public static AccessLevel fromName(final String name) {
        return names.get(name);
      }
    
      public static AccessLevel fromValue(final int value) {
        return values.get(value);
      }
    }
    
    0 讨论(0)
  • 2020-11-28 01:35

    org.apache.commons.lang.enums.ValuedEnum;

    To save me writing loads of boilerplate code or duplicating code for each Enum, I used Apache Commons Lang's ValuedEnum instead.

    Definition:

    public class NRPEPacketType extends ValuedEnum {    
        public static final NRPEPacketType TYPE_QUERY = new NRPEPacketType( "TYPE_QUERY", 1);
        public static final NRPEPacketType TYPE_RESPONSE = new NRPEPacketType( "TYPE_RESPONSE", 2);
    
        protected NRPEPacketType(String name, int value) {
            super(name, value);
        }
    }
    

    Usage:

    int -> ValuedEnum:

    NRPEPacketType packetType = 
     (NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);
    
    0 讨论(0)
提交回复
热议问题