5

We use code values in our database, and Enums in Java. When querying the database, we need to take a code value and get an Enum instance.

Is it overkill to have a HashMap to avoid iteration? What would you do? Is there an easier way?

public enum SomeEnum
{
    TYPE_A(2000), TYPE_B(2001);

    private int codeValue;

    private static HashMap<Integer, SomeEnum> codeValueMap = new HashMap<Integer, SomeEnum>(2);

    static
    {
        for (SomeEnum  type : SomeEnum.values())
        {
            codeValueMap.put(type.codeValue, type);
        }
    }

    //constructor and getCodeValue left out      

    public static SomeEnum getInstanceFromCodeValue(int codeValue)
    {
        return codeValueMap.get(codeValue);
    }
}
Andy
  • 8,841
  • 8
  • 45
  • 68
  • 1
    I see nothing wrong with your approach... in fact, it looks good to me. – limc Feb 22 '11 at 02:10
  • Thanks, I guess my main concern is memory usage, and if it is worth it. Perhaps I am over thinking this. – Andy Feb 22 '11 at 02:16
  • 1
    Using Map like you do is probably the preferred way for lookup if you have tons of enums... see this related post: http://stackoverflow.com/questions/1080904/how-can-i-lookup-a-java-enum-from-its-string-value – limc Feb 22 '11 at 02:21

6 Answers6

4

That's exactly the approach I'd take to solve that particular problem. I see nothing wrong with it from a design point of view, it's intuitive, efficient and (as far as I can see) does exactly what it should.

The only other sensible approach I can think of would be to have the map in a separate class and then call that class to update the map from SomeEnum's constructor. Depending on the use case, this separation could be beneficial - but unless it would have a hard benefit I would take your approach and encapsulate everything within the enum itself.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
1

Thanks, I guess my main concern is memory usage, and if it is worth it.

Unless that enum has thousands of values, memory usage will be trivial. (And if it does have thousands of values, then using iteration to do the lookup would be a major performance killer.)

This is a sensible use of memory, IMO.

Perhaps I am over thinking this.

Perhaps you are.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

I think in this case we can't avoid iteration. It's either HashMap doing it, or we wrote our own iteration code. If performance really does matter maybe you can try a binary tree approach.

  • HashMap doesn't iterate, gets perform O(1). – Andy Feb 22 '11 at 02:38
  • The get method from HashMap will eventually calling some method which performs looping through all of the keys to find the matched key, if you see the source code of HashMap.java. So at the end of the day you'll always be looping/iterating through all of the keys. –  Apr 08 '11 at 03:11
  • Hmm, thats interesting. I was thinking a HashMap with a small number of unique ints as keys would never have a collision. This the performance of get would never degrade beyond O(1), is this not accurate? – Andy Apr 08 '11 at 15:45
  • You would only iterate over all elements if every element had the same hash value and thus all values collided into the same bucket. In this case a HashMap degenerates into a LinkedList. – sksamuel May 15 '11 at 17:53
1

That's fine. Don't worry about tiny performance differences.

One would think that if there are only two instances for an enum, like in your example, a trivial code of iterating would be faster:

public static SomeEnum getInstanceFromCodeValue(int codeValue)
{
    for (SomeEnum  type : SomeEnum.values()) {
        if(type.codeValue == codeValue)
            return type;
    }
}

But there's a hidden cost, quite expensive one if we do care about performane at such level. It's fixable, but you need to see it first:)

eckes
  • 10,103
  • 1
  • 59
  • 71
irreputable
  • 44,725
  • 9
  • 65
  • 93
1

If your enum space is dense, that is, not a lot of unused values, you could use the toString() and valueOf() methods. Name your values with a common string prefix, then attach the prefix before using valueOf() and strip it after using toString(). This has the disadvantage that you would have to convert to a numeric value if that's how it's stored in your database.

Alternatively, you could add common methods for conversion and assign your database value to a specific enum value.

Both these techniques have the advantage of leveraging the design of enum classes.

There is a lot of good, mind-bending information about enums (and Java, in general) at http://mindprod.com/jgloss/enum.html.

Though, there's nothing wrong with your way if it does the job you want.

Suncat2000
  • 1,105
  • 1
  • 14
  • 17
0

To get the ID:

EnumDay day = EnumDay.WEDNESDAY;
int myID = day.ordinal();

To load the day from the myID:

EnumDay dayCopy = EnumDay.values()[myID];

ope
  • 67
  • 1
  • 6