Convert from enum ordinal to enum type

JavaEnums

Java Problem Overview


I've the enum type ReportTypeEnum that get passed between methods in all my classes but I then need to pass this on the URL so I use the ordinal method to get the int value. After I get it in my other JSP page, I need to convert it to back to an ReportTypeEnum so that I can continue passing it.

How can I convert ordinal to the ReportTypeEnum?

Using Java 6 SE.

Java Solutions


Solution 1 - Java

To convert an ordinal into its enum represantation you might want to do this:

ReportTypeEnum value = ReportTypeEnum.values()[ordinal];

Please notice the array bounds.

Note that every call to values() returns a newly cloned array which might impact performance in a negative way. You may want to cache the array if it's going to be called often.

Code example on how to cache values().


This answer was edited to include the feedback given inside the comments

Solution 2 - Java

This is almost certainly a bad idea. Certainly if the ordinal is de-facto persisted (e.g. because someone has bookmarked the URL) - it means that you must always preserve the enum ordering in future, which may not be obvious to code maintainers down the line.

Why not encode the enum using myEnumValue.name() (and decode via ReportTypeEnum.valueOf(s)) instead?

Solution 3 - Java

If I'm going to be using values() a lot:

enum Suit {
   Hearts, Diamonds, Spades, Clubs;
   public static final Suit values[] = values();
}

Meanwhile wherever.java:

Suit suit = Suit.values[ordinal];

If you want the array to be private, be my guest:

private static final Suit values[] = values();
public static Suit get(int ordinal) { return values[ordinal]; }

...

Suit suit = Suit.get(ordinal);

Mind your array bounds.

Solution 4 - Java

I agree with most people that using ordinal is probably a bad idea. I usually solve this problem by giving the enum a private constructor that can take for example a DB value then create a static fromDbValue function similar to the one in Jan's answer.

public enum ReportTypeEnum {
    R1(1),
    R2(2),
    R3(3),
    R4(4),
    R5(5),
    R6(6),
    R7(7),
    R8(8);

    private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);	
    private static Map<Integer, ReportTypeEnum> lookup;
    private Integer dbValue;

    private ReportTypeEnum(Integer dbValue) {
        this.dbValue = dbValue;
    }
    

    static {
        try {
            ReportTypeEnum[] vals = ReportTypeEnum.values();
            lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);

            for (ReportTypeEnum  rpt: vals)
                lookup.put(rpt.getDbValue(), rpt);
         }
         catch (Exception e) {
             // Careful, if any exception is thrown out of a static block, the class
             // won't be initialized
             log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
         }
    }

    public static ReportTypeEnum fromDbValue(Integer dbValue) {
        return lookup.get(dbValue);
    }

    public Integer getDbValue() {
        return this.dbValue;
    }

}

Now you can change the order without changing the lookup and vice versa.

Solution 5 - Java

You could use a static lookup table:

public enum Suit {
  spades, hearts, diamonds, clubs;

  private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();

  static {
    int ordinal = 0;
    for (Suit suit : EnumSet.allOf(Suit.class)) {
      lookup.put(ordinal, suit);
      ordinal+= 1;
    }
  }

  public Suit fromOrdinal(int ordinal) {
    return lookup.get(ordinal);
  }
}

Solution 6 - Java

This is what I use. I make no pretense that it's far less "efficient" than the simpler solutions above. What it does do is provide a much clearer exception message than "ArrayIndexOutOfBounds" when an invalid ordinal value is used in the solution above.

It utilizes the fact that EnumSet javadoc specifies the iterator returns elements in their natural order. There's an assert if that's not correct.

The JUnit4 Test demonstrates how it's used.

 /**
 * convert ordinal to Enum
 * @param clzz may not be null
 * @param ordinal
 * @return e with e.ordinal( ) == ordinal
 * @throws IllegalArgumentException if ordinal out of range
 */
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
	EnumSet<E> set = EnumSet.allOf(clzz);
	if (ordinal < set.size()) {
		Iterator<E> iter = set.iterator();
		for (int i = 0; i < ordinal; i++) {
			iter.next();
		}
		E rval = iter.next();
		assert(rval.ordinal() == ordinal);
		return rval;
	}
	throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}

@Test
public void lookupTest( ) {
	java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
	System.out.println(tu);
}
    

Solution 7 - Java

Safety first (with Kotlin):

// Default to null
EnumName.values().getOrNull(ordinal)

// Default to a value
EnumName.values().getOrElse(ordinal) { EnumName.MyValue }

Solution 8 - Java

This is what I do on Android with Proguard:

public enum SomeStatus {
    UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order

    private static SomeStatus[] values = null;
    public static SomeStatus fromInteger(int i) {
        if(SomeStatus.values == null) {
            SomeStatus.values = SomeStatus.values();
        }
        if (i < 0) return SomeStatus.values[0];
        if (i >= SomeStatus.values.length) return SomeStatus.values[0];
        return SomeStatus.values[i];
    }
}

it's short and I don't need to worry about having an exception in Proguard

Solution 9 - Java

You can define a simple method like:

public enum Alphabet{
    A,B,C,D;

    public static Alphabet get(int index){
        return Alphabet.values()[index];
    }
}

And use it like:

System.out.println(Alphabet.get(2));

Solution 10 - Java

public enum Suit implements java.io.Serializable, Comparable<Suit>{
  spades, hearts, diamonds, clubs;
  private static final Suit [] lookup  = Suit.values();
  public Suit fromOrdinal(int ordinal) {
	if(ordinal< 1 || ordinal> 3) return null;
	return lookup[value-1];
  }
}

the test class

public class MainTest {
    public static void main(String[] args) {
        Suit d3 = Suit.diamonds;
        Suit d3Test = Suit.fromOrdinal(2);
        if(d3.equals(d3Test)){
            System.out.println("Susses");
        }else System.out.println("Fails");
    }
}

I appreciate that you share with us if you have a more efficient code, My enum is huge and constantly called thousands of times.

Solution 11 - Java

So one way is to doExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal]; which works and its easy, however, as mentioned before, ExampleEnum.values() returns a new cloned array for every call. That can be unnecessarily expensive. We can solve that by caching the array like so ExampleEnum[] values = values(). It is also "dangerous" to allow our cached array to be modified. Someone could write ExampleEnum.values[0] = ExampleEnum.type2; So I would make it private with an accessor method that does not do extra copying.

private enum ExampleEnum{
	type0, type1, type2, type3;
	private static final ExampleEnum[] values = values();
	public static ExampleEnum value(int ord) {
		return values[ord];
	}
}

You would use ExampleEnum.value(ordinal) to get the enum value associated with ordinal

Solution 12 - Java

Every enum has name(), which gives a string with the name of enum member.

Given enum Suit{Heart, Spade, Club, Diamond}, Suit.Heart.name() will give Heart.

Every enum has a valueOf() method, which takes an enum type and a string, to perform the reverse operation:

Enum.valueOf(Suit.class, "Heart") returns Suit.Heart.

Why anyone would use ordinals is beyond me. It may be nanoseconds faster, but it is not safe, if the enum members change, as another developer may not be aware some code is relying on ordinal values (especially in the JSP page cited in the question, network and database overhead completely dominates the time, not using an integer over a string).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLennieView Question on Stackoverflow
Solution 1 - JavaJoachim SauerView Answer on Stackoverflow
Solution 2 - Javaoxbow_lakesView Answer on Stackoverflow
Solution 3 - JavaQEDView Answer on Stackoverflow
Solution 4 - Javajmkelm08View Answer on Stackoverflow
Solution 5 - JavaJanView Answer on Stackoverflow
Solution 6 - JavagerardwView Answer on Stackoverflow
Solution 7 - JavaWesty92View Answer on Stackoverflow
Solution 8 - JavaSomeone SomewhereView Answer on Stackoverflow
Solution 9 - JavaAmir FoView Answer on Stackoverflow
Solution 10 - JavaAr majView Answer on Stackoverflow
Solution 11 - Javajoe pelletierView Answer on Stackoverflow
Solution 12 - JavaTony BenBrahimView Answer on Stackoverflow