The old way, if we want to switch on some complex bitmask, we could easily do it like this (a random example from the top of my head to demonstrate the problem):
private static final int MAN = 0x00000001; private static final int WOMAN = 0x00000002;
Currently, since we use enums and EnumSets , I would sometimes like to do a similar thing:
enum Human { MAN, WOMAN, DEAD; // etc. } public void doStuff(EnumSet human) { switch (human) { case Human.MAN | Human.DEAD: // do something break; // more common cases } }
which does not work, because we can only switch on the value of int , enum or String . At this point, I realized that this is not possible, although enum values are basically just hidden integers. But I like to dig around, and the function looks very useful, so:
private static final EnumSet<Human> DEAD_MAN = EnumSet.of(Human.MAN, Human.DEAD); public void doStuff(EnumSet human) { switch (human) { case DEAD_MAN:
Still out of luck. Knowing the trick to enable Strings and that EnumSets are actually 64-bit fields (or arrays of them), I would also try:
switch (human.hashCode()) { case (Human.MAN.hashCode() | Human.DEAD.hashCode()):
thinking that when Human hashCode() is correctly implemented to give consistent results, it can work. Nope
java.lang.Error: Unresolved compilation problem: case expressions must be constant expressions
Now I wonder why there is no way to do this. I always thought of enums and EnumSets in Java as the correct replacement for these old-school bit fields, but here it seems that the new methods cannot handle more complex cases.
The correct kind of solution sucks compared to any of the switch features:
public void doStuff(EnumSet human) { if (human.contains(Human.MAN) && human.contains(Human.DEAD)) {
In particular, since the introduction of switch on Strings , I believe that there are at least two possible implementations of switch on EnumSets :
- In
case (Human.MAN | Human.DEAD) expressions case (Human.MAN | Human.DEAD) simply use compile-time type checking and ordinal() instead of the enumerations themselves. - Using the same trick as for strings .
- At the time of compilation, calculate
hashCode() the name value of the enumeration values (and, possibly, something extra - the number of values in the enumeration, ordinal() , etc.), all static and constant from compilation time). Yes, that would mean changing the hashCode() any of the EnumSet or enum classes. - instead of the enumerations themselves
Now, is there any serious obstacle that I did not take into account (I can come up with a few, everything can be easily overcome) that would make this impossible to implement? Or am I right that this is really possible, but not enough for Oracle to implement it, because it is not used so often?
In addition, let me say that this is a purely academic question, perhaps without a good answer (I don’t know, I would not ask otherwise). I can make this community wiki if it proves incontrovertible. However, I could not find the answer (or even anyone discussing it) anywhere, so here it is.