130

I'm currently creating integer constants in the following manner.

public class Constants {
    public static int SIGN_CREATE=0;
    public static int SIGN_CREATE=1;
    public static int HOME_SCREEN=2;
    public static int REGISTER_SCREEN=3;
}

When i try to do this in enum manner

public enum PAGE{SIGN_CREATE,SIGN_CREATE,HOME_SCREEN,REGISTER_SCREEN}

and When i used PAGE.SIGN_CREATE it should return 1;

gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
Labeeb Panampullan
  • 34,521
  • 28
  • 94
  • 112
  • 10
    That won't compile; you've defined "SIGN_CREATE" twice. Also, those aren't constants -- they're not "final". – BlairHippo Oct 21 '10 at 17:47

6 Answers6

224

Well, you can't quite do it that way. PAGE.SIGN_CREATE will never return 1; it will return PAGE.SIGN_CREATE. That's the point of enumerated types.

However, if you're willing to add a few keystrokes, you can add fields to your enums, like this:


    public enum PAGE{
        SIGN_CREATE(0),
        SIGN_CREATE_BONUS(1),
        HOME_SCREEN(2),
        REGISTER_SCREEN(3);

        private final int value;

        PAGE(final int newValue) {
            value = newValue;
        }

        public int getValue() { return value; }
    }

And then you call PAGE.SIGN_CREATE.getValue() to get 0.

expert
  • 29,290
  • 30
  • 110
  • 214
BlairHippo
  • 9,502
  • 10
  • 54
  • 78
  • 11
    This is actually not true. You can do PAGE.SIGN_CREATE.ordinal(). This would return 0. Probably this anwser is related to a java version, that didn't have this feature, yet. – TheTrowser Jul 01 '15 at 13:36
  • 1
    What of you want to mix numbers and chars up within a single enum? E.g. if I want an enum to store 0, 1 and X? Thank you!! – joninx Dec 23 '15 at 11:23
  • 1
    @BlairHippo: Can I do something like `PAGE pageEnum = PAGE(0)`. In simple words I have a value with me and I want to get the corresponding enum with selected value. Can you answer? – Anas Azeem Apr 25 '16 at 10:39
  • 1
    How would you use this Enum in a switch statement? – Pierre Jun 24 '19 at 10:11
  • @Pierre have you found any solution? I'm also going through the same requirement, Thanks – codeSeeker Jun 30 '20 at 17:33
  • @codeSeeker You just use the enum as per normal. `switch (obj.getPage()) { case SIGN_CREATE: break; case HOME_SCREEN: break; }` – Pierre Jul 01 '20 at 04:49
  • @TheTrowser As far as I understood the question, the OP wants to store custom constants. The numbers returned by ordinal() are only related to the order of declaration (which just happens to be the same in this example), so this answer is correct and useful even with ordinal() existing. – julaine Nov 11 '22 at 09:56
  • @AnasAzeem: If you use ordinal(), the values could change if your code is modified – Joey Carlisle Feb 02 '23 at 23:10
27

The most common valid reason for wanting an integer constant associated with each enum value is to interoperate with some other component which still expects those integers (e.g. a serialization protocol which you can't change, or the enums represent columns in a table, etc).

In almost all cases I suggest using an EnumMap instead. It decouples the components more completely, if that was the concern, or if the enums represent column indices or something similar, you can easily make changes later on (or even at runtime if need be).

 private final EnumMap<Page, Integer> pageIndexes = new EnumMap<Page, Integer>(Page.class);
 pageIndexes.put(Page.SIGN_CREATE, 1);
 //etc., ...

 int createIndex = pageIndexes.get(Page.SIGN_CREATE);

It's typically incredibly efficient, too.

Adding data like this to the enum instance itself can be very powerful, but is more often than not abused.

Edit: Just realized Bloch addressed this in Effective Java / 2nd edition, in Item 33: Use EnumMap instead of ordinal indexing.

Frankie
  • 24,627
  • 10
  • 79
  • 121
Mark Peters
  • 80,126
  • 17
  • 159
  • 190
  • +1 on the EnumMap recommendation. – I82Much Oct 21 '10 at 21:35
  • 2
    That's also quite verbose. It means you keep an entirely separate data structure just to have a mapping from key to a derived numeric index. Bloch also (Item 31) suggests for simple integer index values to use the pattern outlined in @BlairHippo's answer to this question. – Adam Parkin Oct 10 '13 at 20:37
19

You can use ordinal. So PAGE.SIGN_CREATE.ordinal() returns 1.

EDIT:

The only problem with doing this is that if you add, remove or reorder the enum values you will break the system. For many this is not an issue as they will not remove enums and will only add additional values to the end. It is also no worse than integer constants which also require you not to renumber them. However it is best to use a system like:

public enum PAGE{
  SIGN_CREATE0(0), SIGN_CREATE(1) ,HOME_SCREEN(2), REGISTER_SCREEN(3)

  private int id;

  PAGE(int id){
    this.id = id;
  }

  public int getID(){
    return id;
  }

}

You can then use getID. So PAGE.SIGN_CREATE.getID() returns 1.

Adam
  • 43,763
  • 16
  • 104
  • 144
  • 3
    Bad idea though, as it will change when the ordering of the constants in the class declaration changes. – Michael Borgwardt Oct 21 '10 at 21:23
  • 1
    @Michael - That's a good point. I added an additional approach to avoid that problem. – Adam Oct 21 '10 at 21:48
  • -1 It might have changed in the 12 years since you answered this, but the Ordinal value is the first value, which is 0. From the doc you posted: `Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero).` There are also many other reasons to not follow this method, see this answer: https://stackoverflow.com/questions/44654291/is-it-good-practice-to-use-ordinal-of-enum – cjnash May 12 '22 at 14:14
7

I found this to be helpful:

http://dan.clarke.name/2011/07/enum-in-java-with-int-conversion/

public enum Difficulty
{
    EASY(0),
    MEDIUM(1),
    HARD(2);

    /**
    * Value for this difficulty
    */
    public final int Value;

    private Difficulty(int value)
    {
        Value = value;
    }

    // Mapping difficulty to difficulty id
    private static final Map<Integer, Difficulty> _map = new HashMap<Integer, Difficulty>();
    static
    {
        for (Difficulty difficulty : Difficulty.values())
            _map.put(difficulty.Value, difficulty);
    }

    /**
    * Get difficulty from value
    * @param value Value
    * @return Difficulty
    */
    public static Difficulty from(int value)
    {
        return _map.get(value);
    }
}
Clayton Bell
  • 424
  • 4
  • 4
3

You could store that const value in the enum like so. But why even use the const? Are you persisting the enum's?

public class SO3990319 {
   public static enum PAGE {
      SIGN_CREATE(1);
      private final int constValue;

      private PAGE(int constValue) {
         this.constValue = constValue;
      }

      public int constValue() {
         return constValue;
      }
   }

   public static void main(String[] args) {
      System.out.println("Name:    " + PAGE.SIGN_CREATE.name());
      System.out.println("Ordinal: " + PAGE.SIGN_CREATE.ordinal());
      System.out.println("Const:   " + PAGE.SIGN_CREATE.constValue());

      System.out.println("Enum: " + PAGE.valueOf("SIGN_CREATE"));
   }
}

Edit:

It depends on what you're using the int's for whether to use EnumMap or instance field.

TJR
  • 3,617
  • 8
  • 38
  • 41
  • I am facing the problem that I couldn't pass enum value to switch case! "case Actions.CREATE.getAction()" it gives an error "case expressions must be constant expressions" – Mariam A. Moustafa Dec 15 '16 at 10:42
  • 1
    Actions.CREATE is the enum. #getAction() isn't... – TJR Dec 16 '16 at 13:43
0

if you want to be able to convert integer back to corresponding enum with selected value see Constants.forValue(...) in below auto generated code but if not the answer of BlairHippo is best way to do it.

public enum Constants
{
SIGN_CREATE(0),
SIGN_CREATE(1),
HOME_SCREEN(2),
REGISTER_SCREEN(3);

    public static final int SIZE = java.lang.Integer.SIZE;

    private int intValue;
    private static java.util.HashMap<Integer, Constants> mappings;
    private static java.util.HashMap<Integer, Constants> getMappings()
    {
        if (mappings == null)
        {
            synchronized (Constants.class)
            {
                if (mappings == null)
                {
                    mappings = new java.util.HashMap<Integer, Constants>();
                }
            }
        }
        return mappings;
    }

    private Constants(int value)
    {
        intValue = value;
        getMappings().put(value, this);
    }

    public int getValue()
    {
        return intValue;
    }

    public static Constants forValue(int value)
    {
        return getMappings().get(value);
    }
}
Top-Master
  • 7,611
  • 5
  • 39
  • 71