396

What is the correct way to cast an Int to an enum in Java given the following enum?

public enum MyEnum { EnumValue1, EnumValue2 } MyEnum enumValue = (MyEnum) x; //Doesn't work??? 
0

17 Answers 17

664

Try MyEnum.values()[x] where x must be 0 or 1, i.e. a valid ordinal for that enum.

Note that in Java enums actually are classes (and enum values thus are objects) and thus you can't cast an int or even Integer to an enum.

Sign up to request clarification or add additional context in comments.

5 Comments

+1: You may want to cache MyEnum.values() as its expensive. i.e. if you call it hundreds of times.
@PeterLawrey Just for completeness, can you explain why it should be slow? I see no obvious reason for it.
@Tarrasch as arrays are mutable, values() must return a copy of the array of elements just in case you happen to change it. Creating this copy each time is relatively expensive.
@PeterLawrey I've been using to much haskell lately (where everything is immutable)! Thanks for your clear and concise explanation. :)
If using spring a good way to 'cache' this would be just to declare the enum as a singleton bean in a Configuration class somewhere.
192

MyEnum.values()[x] is an expensive operation. If the performance is a concern, you may want to do something like this:

public enum MyEnum { EnumValue1, EnumValue2; public static MyEnum fromInteger(int x) { switch(x) { case 0: return EnumValue1; case 1: return EnumValue2; } return null; } } 

10 Comments

If you want to avoid the switch maintenance, then on the using class: private final MyEnum[] myEnumValues = MyEnum.values(); Then usage: myEnum = myEnumValues[i];
@GiliNachum said it in a weird way, but the problem with this solution is maintainability. It goes against the DRY principle, which means whenever the enum values is changed (reordered, value(s) added, value(s) removed) the switch statement has to simultaneously be updated. Gili's comment forces Java to maintain consistency with the list of enum values, changes to the enum values doesn't affect that approach at all.
@LorenzoPolidori, Can you explain why you regard MyEnum.values()[x] as an expensive operation. I don't know how it works in details, but to me it seems like accessing an element in an Array would be no big deal, aka constant time. If the array has to be build it takes O(n) time, which is the same runnning time as your solution.
@brunsgaard I assume values() generates a new array each time, because arrays are mutable so it wouldn't be safe to return the same one multiple times. Switch statements are not necessarily O(n), they can be compiled to jump tables. So Lorenzo's claims seem justified.
@Johnson Gili's version doesn't require any additional code changes outside of the changes in the Enum declaration. If you add a new item to the enum, myEnum = myEnumValues[i] will still return the ith item in the Enum without changes.
|
55

You can try like this.
Create Class with element id.

 public Enum MyEnum { THIS(5), THAT(16), THE_OTHER(35); private int id; // Could be other data type besides int private MyEnum(int id) { this.id = id; } public static MyEnum fromId(int id) { for (MyEnum type : values()) { if (type.getId() == id) { return type; } } return null; } } 

Now Fetch this Enum using id as int.

MyEnum myEnum = MyEnum.fromId(5); 

Comments

54

If you want to give your integer values, you can use a structure like below

public enum A { B(0), C(10), None(11); int id; private A(int i){id = i;} public int GetID(){return id;} public boolean IsEmpty(){return this.equals(A.None);} public boolean Compare(int i){return id == i;} public static A GetValue(int _id) { A[] As = A.values(); for(int i = 0; i < As.length; i++) { if(As[i].Compare(_id)) return As[i]; } return A.None; } } 

6 Comments

+1 because it highlights the fact, that values dont have to be consecutive.
Also, this seems to be the only answer that works if you want a sparse (or repeated) set of integer values rather than using the default ordinals from 0..(count-1). That can be important if you're interacting with existing code, such as over a network.
Worth pointing out that as in the above answers, caching the result of values() is probably worthwhile, so as to avoid a memory allocation and arraycopy every time you invoke it.
And, depending on the length of your enum, you may want to create a HashMap or use a binary search or something for this lookup, rather than doing a linear search every time.
This should be the right way and best practice to convert int to enum, and i think you can simplify the problem by public static A GetValue(int _id) { for(A a:A.values() { if(a.getId()==_id) { return a; }} return null; } Get rid of the None, isEmpty() and compare() stuff.
|
22

I cache the values and create a simple static access method:

public static enum EnumAttributeType { ENUM_1, ENUM_2; private static EnumAttributeType[] values = null; public static EnumAttributeType fromInt(int i) { if(EnumAttributeType.values == null) { EnumAttributeType.values = EnumAttributeType.values(); } return EnumAttributeType.values[i]; } } 

6 Comments

This is solution I use now. But IMHO it is less confusing if you don't give the field values the same name as the method values(). I uses cachedValues for field name.
Efficient and elegant; copied and pasted into my project :) The only thing I changed is the fromInt(int i), which I'm just called from(int i) because it's a bit redundant to have int twice in the signature.
why not initializing from beginning? why waiting for the first hit?
@kaiser there's no place to get values() "from the beginning". The enum constructors are per enum value so in those constructors this.values() gives -java.lang.NullPointerException: Cannot invoke "[LFooBar;.clone()" because "FooBar.$VALUES" is null
I think that fromOrdinal(int) might be a better name since there's a lot of alternative solutions like @Doctor's answer here that use a synthetic/explicit int value, like id or value.
|
12

Java enums don't have the same kind of enum-to-int mapping that they do in C++.

That said, all enums have a values method that returns an array of possible enum values, so

MyEnum enumValue = MyEnum.values()[x]; 

should work. It's a little nasty and it might be better to not try and convert from ints to Enums (or vice versa) if possible.

Comments

10

This not something that is usually done, so I would reconsider. But having said that, the fundamental operations are: int --> enum using EnumType.values()[intNum], and enum --> int using enumInst.ordinal().

However, since any implementation of values() has no choice but to give you a copy of the array (java arrays are never read-only), you would be better served using an EnumMap to cache the enum --> int mapping.

2 Comments

Re "This not something that is usually done": Common case where it is useful: enum corresponds to int values stored in a database.
@ToolmakerSteve you are absolutely right that the mappings are required. But would you want to leave that sort of encoding to some O-R mapper or some toolkit/library?
8

Use MyEnum enumValue = MyEnum.values()[x];

Comments

6

Here's the solution I plan to go with. Not only does this work with non-sequential integers, but it should work with any other data type you may want to use as the underlying id for your enum values.

public Enum MyEnum { THIS(5), THAT(16), THE_OTHER(35); private int id; // Could be other data type besides int private MyEnum(int id) { this.id = id; } public int getId() { return this.id; } public static Map<Integer, MyEnum> buildMap() { Map<Integer, MyEnum> map = new HashMap<Integer, MyEnum>(); MyEnum[] values = MyEnum.values(); for (MyEnum value : values) { map.put(value.getId(), value); } return map; } } 

I only need to convert id's to enums at specific times (when loading data from a file), so there's no reason for me to keep the Map in memory at all times. If you do need the map to be accessible at all times, you can always cache it as a static member of your Enum class.

1 Comment

IMHO if I was concerned about memory usage, I would dynamically create the HashMap - like @ossys but with different code when cache is null, then add a second method clearCachedValues when you are done using it (that sets the private field back to null). I consider MyEnum.fromInt(i) easier to understand than passing around a map object.
6

In case it helps others, the option I prefer, which is not listed here, uses Guava's Maps functionality:

public enum MyEnum { OPTION_1(-66), OPTION_2(32); private int value; private MyEnum(final int value) { this.value = value; } public int getValue() { return this.value; } private static ImmutableMap<Integer, MyEnum> reverseLookup = Maps.uniqueIndex(Arrays.asList(MyEnum.values())), MyEnum::getValue); public static MyEnum fromInt(final int id) { return reverseLookup.getOrDefault(id, OPTION_1); } } 

With the default you can use null, you can throw IllegalArgumentException or your fromInt could return an Optional, whatever behavior you prefer.

3 Comments

You should mention you're using Guava. Or you can use streams: Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
Might want to define a getValue() method also.
@shmosel Oops, I missed the getValue function, thanks. Typing generic versions into stackoverflow does not always pan out. Added comment about using Guava with a link. Prefer the Guava method to streams.
6

Based on @ChadBefus 's answer and @shmosel comment, I'd recommend using this. (Efficient lookup, and works on pure java >= 8)

import java.util.stream.Collectors; import java.util.function.Function; import java.util.Map; import java.util.Arrays; public enum MyEnum { OPTION_1(-66), OPTION_2(32); private int value; private MyEnum(final int value) { this.value = value; } public int getValue() { return this.value; } private static Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity())); public static MyEnum fromInt(final int id) { return reverseLookup.getOrDefault(id, OPTION_1); } public static void main(String[] args) { System.out.println(fromInt(-66).toString()); } } 

2 Comments

Will this work on double,short,float,long
@deepakl.2000 : Enum values are integer values, so supporting only int is valid. I don't think it's possible to have an Enum that has a float ordinal for example.
4

You can iterate over values() of enum and compare integer value of enum with given id like below:

public enum TestEnum { None(0), Value1(1), Value2(2), Value3(3), Value4(4), Value5(5); private final int value; private TestEnum(int value) { this.value = value; } public int getValue() { return value; } public static TestEnum getEnum(int value){ for (TestEnum e:TestEnum.values()) { if(e.getValue() == value) return e; } return TestEnum.None;//For values out of enum scope } } 

And use just like this:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
I hope this helps ;)

Comments

3

Wrote this implementation. It allows for missing values, negative values and keeps code consistent. The map is cached as well. Uses an interface and needs Java 8.

Enum

public enum Command implements OrdinalEnum{ PRINT_FOO(-7), PRINT_BAR(6), PRINT_BAZ(4); private int val; private Command(int val){ this.val = val; } public int getVal(){ return val; } private static Map<Integer, Command> map = OrdinalEnum.getValues(Command.class); public static Command from(int i){ return map.get(i); } } 

Interface

public interface OrdinalEnum{ public int getVal(); @SuppressWarnings("unchecked") static <E extends Enum<E>> Map<Integer, E> getValues(Class<E> clzz){ Map<Integer, E> m = new HashMap<>(); for(Enum<E> e : EnumSet.allOf(clzz)) m.put(((OrdinalEnum)e).getVal(), (E)e); return m; } } 

1 Comment

Review :: Can you please write code comments so that developers can understand the step by step logic
1

In Kotlin:

enum class Status(val id: Int) { NEW(0), VISIT(1), IN_WORK(2), FINISHED(3), CANCELLED(4), DUMMY(5); companion object { private val statuses = Status.values().associateBy(Status::id) fun getStatus(id: Int): Status? = statuses[id] } } 

Usage:

val status = Status.getStatus(1)!! 

Comments

0

A good option is to avoid conversion from int to enum: for example, if you need the maximal value, you may compare x.ordinal() to y.ordinal() and return x or y correspondingly. (You may need to re-order you values to make such comparison meaningful.)

If that is not possible, I would store MyEnum.values() into a static array.

1 Comment

If you get int from DB and want to convert it into Enum, which I think is a very common task, you'll need int -> enum conversion, IMO..
0

This is the same answer as the doctors but it shows how to eliminate the problem with mutable arrays. If you use this kind of approach because of branch prediction first if will have very little to zero effect and whole code only calls mutable array values() function only once. As both variables are static they will not consume n * memory for every usage of this enumeration too.

private static boolean arrayCreated = false; private static RFMsgType[] ArrayOfValues; public static RFMsgType GetMsgTypeFromValue(int MessageID) { if (arrayCreated == false) { ArrayOfValues = RFMsgType.values(); } for (int i = 0; i < ArrayOfValues.length; i++) { if (ArrayOfValues[i].MessageIDValue == MessageID) { return ArrayOfValues[i]; } } return RFMsgType.UNKNOWN; } 

Comments

0
enum MyEnum { A(0), B(1); private final int value; private MyEnum(int val) {this.value = value;} private static final MyEnum[] values = MyEnum.values();//cache for optimization public static final getMyEnum(int value) { try { return values[value];//OOB might get triggered } catch (ArrayOutOfBoundsException e) { } finally { return myDefaultEnumValue; } } } 

3 Comments

@shmosel I believe exceptions are significantly better if the out of bounds are relatively very few.
What is your belief based on?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.