Java wish: A Reversible Enum
One of the biggest feature added with JDK 1.5 is enum support. At last you can use a language construct to define constants in the system rather than using the static final to define the constants. The obvious benefits of enums are type safety and type checking.
Also enums let you define meaningful values for the constants. e.g.
As you can see in the above example, you can use the enum constant PI across your code, but if you wanted to get the value of PI, you can do that by using PI.getValue().
This is where things get a little fuzzy. What if you have a double value representing either PI or LOG_E and you want to find out which constant in MathEnum represents that value? This is the reverse lookup of enum. The Java implementation of enum does not allow reverse lookup by value. It is a very useful feature if you are working with an existing code base and an external system returns values for the constants that need to be translated into Java Enums.
Here is how this problem can be solved by using the Reversible Enum Pattern. First we need to create a ReversibleEnum interface that will mark the Enums as reversible and define the required method.
Next, we need to define a Map that will be used to store the enum constant values and for reverse lookup.
You will notice that in both the ReversibleEnum interface and the ReverseEnumMap class the Generics template is used. This is done to customize these based on the type of the enum that will use them and the type of the value of enum constants. If this sounds confusing, it will become more clear after we see the modified version of the MathEnum class from earlier.
The changes you will notice here are:
MathEnumimplements theReversibleEnuminterface.- New variable for
ReversibleEnumMap - New method
reverse(final Double value)to do the reverse lookup. This is from theReversibleEnuminterface. - New static method
getInstance()that just returns the first constant of the enum. This is kind of a hack to get a reference to an instant of the enum, so that thereverse(..)method could be called on it.
Now to do a reverse lookup on the MathEnum, all you need to do is:
Lets recap all the steps needed to be done to create a reversible enum:
- Define an interface
ReversibleEnum. — One time job. - Define a new class
ReverseEnumMap. — One time job. - Implement the
ReversibleEnuminterface and define a member variable of typeReverseEnumMapin the enum that you want to be reversible. If you do not need the reverse functionality, you don’t need to do any of this.
So, effectively once you have the interface and map class created, it’s minimal effort to create a reversible enum. I wish this was a built-in functionality in the JDK enum implementation.













Sarmad Fayyaz said,
December 5, 2006 @ 1:29 am
Hi,
I was wondering if adding a static method not be good enough. Also by adding a reverse() to the MathEnum class does that make the abstraction kind of fuzzy since now you can say:
MathEnum.LOG_E.reverse(3.14159); // a bit weird
when it should be more like.
MathEnum.getCorrespondingMathEnum(3.14159);
I think it is for this reason JDK does not do this.
Thank You,
Sarmad Fayyaz
Atif Khan said,
December 5, 2006 @ 7:24 am
Sarmad,
You can definitely just implement a static method and get done with it. But when you implement an interface, you are explicitly marking that enum to be reversible. That makes your code more consistent and understandable. Also, by using an interface you can template the
ReverseEnumMapto accept any enumeration that implements theReversibleEnuminterface. As far as invoking the reverse method, there is no way to restrict the invocation as you suggested. It has to be enforced as a guideline in your organization to be done likeMathEnum.getInstance().reverse(3.14159).As far implementing it in JDK, it could have been done the same way
values()is implicitly implemented for all the enums. JDK implicitly exposes this to you. It can be done the same for reverse. Then obviously you will not need the getInstance() method.Carsten Saager said,
December 5, 2006 @ 5:05 pm
To be reversible you also have to have that the values are unique. This is the problem. How do you ensure that a have defined the enum with no duplicate values. After you did that, explain your programmers why they cannot define aliases.
You might guess - I already did this and now I am convinced that looking up the reverse is not necessary - unless you use Java where you cannot control the representation (ordinal) of the enum values.
Atif Khan said,
December 5, 2006 @ 5:13 pm
Why would you have 2 enum constants with the same value? That defeats the whole purpose of enums as they are associated with a namespace. Now, can you have 2 constants for the same thing in the same namespace?
As I said in my post, you don’t really need the reverse functionality if you are writing something new. But, if you deal with the legacy code that uses the old fashioned constants, you need the reverse functionality.
Phillip Rhodes said,
December 5, 2006 @ 10:47 pm
My thinking is, if you have code that requires this functionality, that code needs to be refactored.
Atif Khan said,
December 5, 2006 @ 10:58 pm
Phillip,
I understand your concern and refactoring is indeed the right way to go. The problem is how do you force an external vendor to make changes to their code? In fact there is a lot of Java code out there still written in JDK 1.4 or less.
jack said,
December 6, 2006 @ 3:01 pm
I have done a similiar thing. I wanted my enums to actually contain a constant value. That way I could process incomming messages based on the constant value plus I am persisting the constant value in the database but still have the compile time safety in my code. Even though I have minimized the code that needs to be written for each of these enums the code is exactly the same for every enum. I wish they would allow you to use enums based of your own type. That way I would not have to use the copy and paste method.
Sam said,
December 6, 2006 @ 7:14 pm
I agree with Sarmad - if you’re going to implement such a feature, it makes much more sense as a static lookup method (just like the valueOf() method provided by default). You’re argument for making reverse() non-static seems to be based on the fact that doing it this way allows you to define a common interface for all reversable enums. But a common interface is really only useful if you want to be able to treat ReversableEnum instances polymorphically. Your usage pattern (MathEnum.getInstance().reverse(…)) is explictly non-polymorphic since it requires calling the static ‘getInstance’ method. So there doesn’t seem to be any advantage to implementing the ReversableEnum interface - it just adds complexity. Also, god forbid someone defines an enum without any values (perfectly legal although not very useful) - then your getInstance code blows up.
Abraham Tehrani said,
December 6, 2006 @ 7:18 pm
I think in your example the usage of Enums is wrong. You are mixing public constants with enums. While on the surface they seem the same, they’re not. Anytime you begin to think you need the “value” of an Enum, you should probably think public constants (because that’s what you really need). The whole point of a enum is to abstract out the concrete value.
Please read Effective Java Item 21
Atif Khan said,
December 7, 2006 @ 10:40 am
Abraham,
Thanks for the Effective Java reference. I know that you can create a typesafe enum using classes. I was just trying to bring up the point that the default implementation of enum in Java leaves a lot to be desired. That’s why I say in my post that the enums need to be further refined in the JDK.
One thing I have an issue with is that if you don’t place any significance to the value of the enum constant, then why is it allowed and a valid construct? And if I can define any arbitrary value, then why can’t I do a lookup both ways?
Vinicius Carvalho said,
December 7, 2006 @ 11:25 am
Really nice, great job indeed. It’s funny when the simplest things are right in front of us and we can’t see. Really, really useful pattern, loved it, using it
Best regards
Paul Murray said,
December 7, 2006 @ 8:49 pm
I prefer our method for looking up enums by value. The key is using java.util.EnumSet, and using Intersection types. (read the java language spec for an explanation)
I’ll show you an example, but I will not do the caching, ok? That is left as an exercise for the reader
First: define an interface
interface Valued {
Object getValue();
}
Normally you would make Valued generic (ie, what kind of value), but I will eave it as-is. Generifying it is left as an exercise.
Next, we define a valued enum:
enum Const implements Valued {
PI(3.14159), E(2.1);
Double v;
Const(double v) { this.v = v; }
public Double getValue() { return v;}
}
now, the method to get the enum from the value can be put anywhere. Once again I stress that in real life, you would cache these things. I am not doing that, ok?
class Foo
{
static
E getEnum (Class clazz, Object value)
{
for(E e: EnumSet.allOf(clazz)) {
if(e.getValue().equals(value)) {
return e;
}
}
return null;
}
}
If you do cache values and their enums, then if the code is going to run inside an appserver be sure to make the caching threadsafe, ok?
Paul Murray said,
December 7, 2006 @ 8:52 pm
Arrgh! The thingo stripped out the angle brackets! Let’s try it again. Sorry if this does not post correctly this time either:
class Foo
{
static ‹E extends Enum & Valued›
E getEnum (Class‹E› clazz, Object value)
{
for(E e: EnumSet.allOf(clazz)) {
if(e.getValue().equals(value)) {
return e;
}
}
return null;
}
}
Paul Murray said,
December 7, 2006 @ 8:58 pm
You know, I would very much like it if java accepted unicode ‹ › for generics. I would also like it if it accepted unicode « » for annotations.
«Transient»
«AttributeOverride name=”foo”, column=«Column nullable=false»»
class SomeEntity {
…
}
Oh - also, I would like it if java.lang.Math had a constant with the identifier π for the value Pi (in addition to the current constant named PI).
But it just ain’t going to happen.
If you use an IDE that allows your source to be UTF-8 encoded, you can use greek θ and φ for variable names in your math-related progams.
Sam said,
April 9, 2007 @ 3:44 pm
Hi,
I was wondering if you (Atif Khan) are a student at Parrswood High Scool Y10.
Atif Khan said,
April 13, 2007 @ 6:27 pm
No. I am not.
Atif Khan’s Blog » Blog Archive » Multi-valued Reversible enum in Java said,
April 16, 2007 @ 6:48 pm
[...] Sometime back I proposed a reversible enum pattern in my post. One thing missing from that implementation was the ability to successfully lookup the enum constants in cases where enum constants can have multiple values. To accomplish this, I utilized another feature introduced in Java 5, namely varargs or variable argument support. This way while building the key for the map, we utilize all the values for a constant and use the varargs in the reverse() method of the enum. [...]