views:

99

answers:

2

Hello,

I have a 2 enum values representing a mapping to object which I'm (currently) modeling with a HashMap with the 2 enums values are used as key and the object is the value.

This is inefficient because what I'm doing is creating a new CompositeKey(Enum1 enum1, Enum2 enum2) for each combination of the Enum1.values() x Enum2.values().

I would like to skip the new CompositeKey() issue.

The solution I'm currently think of is Calculation a number representations of from the 2 enums, something like int numericKey = enum1.ordinal() * 0xFFFF + enum2.ordinal(); but then when I'll do map.get(numricKey) I will still be auto boxing to Integer - hence creation new instances.

A perfect solution (IMO) would be Map implementation (doesn't have to be generic...) but I don't think such existing for java.

Another option is probably mapping = new Object[Enum1.values().length][Enum2.values().length] which I will then do lookup with Object = mapping[enum1.ordinal()][enum2.ordinal()] but that seems a bit too "C'ish".

Anyways, runtime performance is the most important aspect here.

Comments are welcome.

Thanks, Maxim.

+1  A: 

I think the CompositeKey approach is the best from a maintenance perspective, because it lets you use the existing collections unchanged. The overhead of creating instances of this object really isn't that high -- most of the instances will be short-lived and never get out of the Eden space (which is both allocated and collected very quickly).

You could also implement Map<Enum1,Map<Enum2,?>>, with EnumMap as your implementation type. However, you'll have to either pre-populate the "outer" maps, or write code to lazily populate it.

But if runtime performance is your top priority, then your idea of using an array is best. I wouldn't implement it as a two-dimensional array, however. Instead, use a one-dimensional array and index with the following:

int index = enum1.ordinal() * _enum1Size + enum2.ordinal;

Wrap it in a class and you're done.

Anon
+6  A: 

Using the ordinal of an enum is a very bad idea because the ordinal is an internal representation of an enum and should never be used in external code. The Enum specification has this to say about ordinal:

Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

I recommend using an EnumMap which is specifically designed such purposes as the one you have. Create an EnumMap<Enum1,EnumMap<Enum2,V>> and populated it using the values of your enums:

for (Enum1 e1: Enum1.values()) {
    map.put(e1, new EnumMap<Enum2,V>());
    for (Enum2 e2 : Enum2.values()) {
        map.get(e1).put(e2, getSomeValue(e1, e2));
    }
}
abhin4v
That is a very good idea which I simply haven't thought of. Thanks.
Maxim Veksler