JMRboosties
JMRboosties

Reputation: 15740

Setting an enum by using an int specific to that enum?

Hey all. So I have a set of enums and a db with integers corresponding to those enums. Something like this, for example:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }
}

I also have a database which only refers to these days by integers, which correspond to their int in the enum set above. What I am looking to do is query a database, which will return an integer, and then set an enumerator to an object based on that integer returned from the db. I could do something like this:

public static Day getDay(int i) {
    switch(i) {
    case 1:
        return Day.SUNDAY;
    case 2: 
        return Day.MONDAY;
    //And so on
    }
}

But for an enum set with over 100 enums inside this doesn't seem very practical.

So is there a way to do this? Again my goal is to simply insert an int value and get back an enumerator without having to create a new method for the many enums in this set. Maybe I should just make this its own class rather than an enumerator, but I was hoping to do it this way. Thanks!

Upvotes: 18

Views: 23163

Answers (6)

Bohemian
Bohemian

Reputation: 424983

Here's a simple implementation that will work:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }

    public static Day forInt(int id) {
        for (Day day : values()) {
            if (day.fId == id) {
                return day;
            }
        }
        throw new IllegalArgumentException("Invalid Day id: " + id);
    }
}

If you know that your enums start counting from 1, you can simply use this instead:

public static Day forInt(int id) {
    return values()[id - 1];
}

Upvotes: 13

Ivo Stoyanov
Ivo Stoyanov

Reputation: 18699

Day myDay = Day.values()[x] - x is the int value

Upvotes: 0

user124
user124

Reputation: 1732

Edited - cache created lazy.

You can create Map<Integer,Day> runtime and use that in getDay implementation.

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    private static Map<Integer,Day> CACHE = null;

    private static void lazyFillCache() {
        if (CACHE != null) return;

        final Map<Integer,Day> c = new HashMap<Integer,Day>();
        for (final Day d : Day.values()) {
            c.put(d.fId, d);
        }

        CACHE = c;
    }

    public static Day getDay(int i) {
        lazyFillCache();
        return CACHE.get(i);
    }

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }
}

Edit - Inspired by Tom Hawtins comment here, you can also use this implementation, which takes advantage of Java class loading capabilities:

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    private static class Cache {
        private static Map<Integer,Day> CACHE = new HashMap<Integer,Day>();

        static {
            for (final Day d : Day.values()) {
                CACHE.put(d.fId, d);
            }
        }
    }

    public static Day getDay(int i) {
        return Cache.CACHE.get(i);
    }

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }
}

Upvotes: 1

Basanth Roy
Basanth Roy

Reputation: 6490

You enum class should have a lookup map built inside as a static variable. Hence your enum class should be something like.

public static enum Day {
    SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5), FRIDAY(6), SATURDAY(7);

    public final int fId;

    private Day(int id) {
        this.fId = id;
    }


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

   static {
   for (Day s : EnumSet.allOf(Day.class))
         lookup.put(s.getIntValue(), s);
   }

   public static Day getValue(int intValue) {
      return lookup.get(intValue);
   }

}

Then to retrieve the correct enum based on an int i, you can just invoke

Day.getValue(i);

This approach will work even if the numbering is non-linear or has gaps in it.

Upvotes: 6

David Z
David Z

Reputation: 131550

Enums have a built-in ID number, the "ordinal," that you can use for this purpose, as long as you have an easy way to get from the number that represents a given value in the database to the ordinal of the enum. Ordinals are assigned to enum values in the order they are declared in the source file, starting from 0, so in your example, SUNDAY would have an ordinal of 0, MONDAY of 1, etc.

In order to use this, you just have to convert the integer stored in the database to its corresponding ordinal, and then use it to access the enum value. So for your example, an implementation might be

private static Day[] values = Day.values();
public static Day getDay(int i) {
    return values[i - 1];
}

If the order of the enum values according to their database IDs is the same order with which they are declared in the source code, then you can pretty much just use the above method as-is (except for changing the class name). Otherwise, you may have to do something a little more complicated to map database values to ordinals; perhaps setting up an array, if the mapping is highly nonlinear.

P.S. And of course if you do this, there would be no use for the fId field.

Upvotes: 9

MRAB
MRAB

Reputation: 20644

Day.values() will return a (zero-based) array of the enum values.

Upvotes: 0

Related Questions