384

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???
trumpetlicks
  • 7,033
  • 2
  • 19
  • 33
Maxim Gershkovich
  • 45,951
  • 44
  • 147
  • 243

17 Answers17

648

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.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Thomas
  • 87,414
  • 12
  • 119
  • 157
  • 127
    +1: You may want to cache `MyEnum.values()` as its expensive. i.e. if you call it hundreds of times. – Peter Lawrey May 04 '11 at 07:27
  • 7
    @PeterLawrey Just for completeness, can you explain why it should be slow? I see no obvious reason for it. – Tarrasch Dec 04 '12 at 00:10
  • 54
    @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. – Peter Lawrey Dec 04 '12 at 08:44
  • 9
    @PeterLawrey I've been using to much haskell lately (where everything is immutable)! Thanks for your clear and concise explanation. :) – Tarrasch Dec 04 '12 at 17:46
  • how to get the 'x' ? – Beeing Jk Oct 05 '17 at 04:41
  • @BeeingJk that `x` is the integer value you want to convert (see the OP's question). Where it comes from is up to you (note: if you can work with enums directly you should do that instead). – Thomas Oct 05 '17 at 08:01
  • @BeeingJk yes, as I wrote: "a valid ordinal for that enum" :) Just note that if you have an enum you might not need the ordinal at all - unless you're serializing it (e.g. to send it to some webservice) but in that case it might be better to use some other representation (e.g. the name etc.) since rearranging enum values might otherwise introduce hard to track bugs. – Thomas Oct 06 '17 at 07:37
  • 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. – Toofy Oct 05 '22 at 14:21
190

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;
    }
}
Lorenzo Polidori
  • 10,332
  • 10
  • 51
  • 60
  • 52
    If you want to avoid the switch maintenance, then on the using class: private final MyEnum[] myEnumValues = MyEnum.values(); Then usage: myEnum = myEnumValues[i]; – Gili Nachum Jun 04 '12 at 18:20
  • 26
    @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. – Dandre Allison Jan 08 '13 at 22:39
  • @DandreAllison what you say is true, I just put forward a possible alternative solution for simple Enums that don't change often. Of course, if you can cache the Enum values in a final property somewhere, this will avoid the maintenance overhead. – Lorenzo Polidori Jan 09 '13 at 12:11
  • 3
    @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 Oct 04 '13 at 18:06
  • In your switch, how about: "case MyEnum.EnumValue1.ordinal()" etc., instead of "case 0". – Bumptious Q Bangwhistle Oct 17 '13 at 10:47
  • 2
    @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. – MikeFHay Jan 24 '14 at 16:41
  • @LorenzoPolidori: wouldn't it be a *lot* easier to maintain a solution that simply caches values(), as suggested by Peter Lawrey? Looks like your solution needs a lot of custom coding per enum class. (+1 because I like the idea of adding that method, I would just change its contents to create and use a cache of values.) – ToolmakerSteve Jun 27 '15 at 01:07
  • How about using the cached values like: private static final MyEnum[] values = MyEnum.values(); public static final getMyEnum(int value) { try { return values[value]; } catch (ArrayOutOfBoundsException e) { } finally { return myDefaultEnumValue; } } – Zoso Dec 14 '15 at 22:58
  • @DandreAllison I wonder why the caching version proposed by Gili will not be affected by changes to the Enum. In case of a change to the Enum, all assignments of the form `myEnum = myEnumValues[i]` need to be checked as well. Or did you mean runtime changes? Maybe I misunderstood your statement. – Johnson Jul 30 '18 at 13:46
  • 1
    @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 `i`th item in the Enum without changes. – Dandre Allison Feb 10 '20 at 02:08
  • 1
    @DandreAllison I can't remember why I asked the above question in the first place. From my current point of view, everything is clear. Maybe I thought you also meant that the client code using the enum does never have to change (obviously it has to adapt to changing semantics of the enum). Reading the comments again, however, it's quite clear that you are just talking about the casting mechanism. Thanks anyway, for clarifying. – Johnson Feb 11 '20 at 08:36
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;
        }
}
Doctor
  • 788
  • 9
  • 12
  • 7
    +1 because it highlights the fact, that values dont have to be consecutive. – rhavin Feb 06 '13 at 17:00
  • 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. – benkc Apr 22 '13 at 22:51
  • 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. – benkc Apr 22 '13 at 22:52
  • 1
    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. – benkc Apr 22 '13 at 22:57
  • 2
    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. – Chris.Zou May 13 '14 at 03:15
  • this may work, but imho its too easy to use in the wrong way by assuming a "normal" enum and doing `A.values()[ some_id ];` which of course wont return `None` if you pass `11` – 463035818_is_not_an_ai Aug 13 '18 at 16:32
  • Can it be like i have a level and then code it like B(level>0 && level<10) C(level>10 && level<20) .......Please help me since i have the following requirement in Java 8 and based on the condition i print output B or print output C. Stuck with this for long time..please help – deepakl.2000 Dec 16 '22 at 16:59
52

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);
Piyush Ghediya
  • 1,754
  • 1
  • 14
  • 17
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];
    }
}
ossys
  • 4,157
  • 5
  • 32
  • 35
  • 4
    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. – ToolmakerSteve Jun 27 '15 at 01:15
  • 3
    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. – pipedreambomb May 18 '17 at 16:05
  • 1
    why not initializing from beginning? why waiting for the first hit? – kaiser Feb 15 '18 at 23:41
  • @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_ – mnsc Jan 18 '23 at 09:28
  • 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`. – mnsc Jan 18 '23 at 09:30
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.

Cameron Skinner
  • 51,692
  • 2
  • 65
  • 86
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.

Maicon Mauricio
  • 2,052
  • 1
  • 13
  • 29
Dilum Ranatunga
  • 13,254
  • 3
  • 41
  • 52
  • 3
    Re "This not something that is usually done": Common case where it is useful: enum corresponds to int values stored in a database. – ToolmakerSteve Jun 27 '15 at 01:09
  • @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? – Dilum Ranatunga Aug 19 '15 at 07:26
8

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

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
w.donahue
  • 10,790
  • 13
  • 56
  • 78
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.

Kevin DiTraglia
  • 25,746
  • 19
  • 92
  • 138
jkindwall
  • 3,816
  • 1
  • 17
  • 17
  • 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. – ToolmakerSteve Jun 27 '15 at 01:23
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.

Chad Befus
  • 1,918
  • 1
  • 18
  • 18
  • 4
    You should mention you're using Guava. Or you can use streams: `Map reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));` – shmosel Nov 16 '17 at 00:53
  • 1
    Might want to define a `getValue()` method also. – shmosel Nov 16 '17 at 00:55
  • @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. – Chad Befus Nov 16 '17 at 01:15
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());
    }
}
Yuki Inoue
  • 3,569
  • 5
  • 34
  • 53
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 ;)

Yashar Aliabbasi
  • 2,663
  • 1
  • 23
  • 35
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;
    }
}
Gerrit Brink
  • 977
  • 3
  • 15
  • 26
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)!!
CoolMind
  • 26,736
  • 15
  • 188
  • 224
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.

18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
  • 2
    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.. – Yuki Inoue Dec 02 '18 at 05:41
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;
}
Ali Akdurak
  • 3,841
  • 1
  • 18
  • 16
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;
        }
    }
}
Zoso
  • 3,273
  • 1
  • 16
  • 27