spilot
spilot

Reputation: 635

Possible to subclass an enum to force compiler to only accept certain enum values?

JavaFX declares the enum KeyCode, which enumerates a code for each key there is on common keyboards. I am currently declaring a function that only makes sense if given a modifier key. It looks like this:

void doStuff(KeyCode c){
  if(!c.isModifierKey()) throw new IllegalArgumentException();
  ...
}

But I think it would be much cleaner if the compiler could make this check for me. So if I could somehow 'extend' KeyCode to a subset that only contains modifier keys, my code would become much cleaner. Does anyone have an idea on how to do this?

Upvotes: 1

Views: 118

Answers (2)

thst
thst

Reputation: 4602

You cannot subclass enum in Java.

You need to define your own KeyCode enum. But I suspect you will not win much clarity here. You may want to encapsulate your if command into an assert method like so:

assertModifierKeyCode(KeyCode c) {
   if(!c.isModifierKey()) throw new IllegalArgumentException();
}

Then your method is a little bit more concise about the meaning:

void doStuff(KeyCode c){
   assertModifierKeyCode(c);
    ...
}

Of course you are free to check the keycode constraint before calling doStuff, then you could have a ModifierCode enum, that you misuse as a filter:

ModifierCode m = ModifierCode.fromKeyCode(c); // could throw Exception
doStuff( m );

...

void doStuff( ModifierCode m ) {
   switch ( m ) {
   case ...
}

To have the KeyCode still available, you construct the ModifierCode with the KeyCode embedded:

public enum ModifierCode {

   LSHIFT(KeyCode.LeftShift),
   RSHIFT(KeyCode.RightSHift)  // bear with me, I dont have KeyCode enum in memory
   ; 

   final private KeyCode keyCode;

   private ModifierCode(KeyCode c) {
       this.keyCode = c;
   }

   public KeyCode getKeyCode() {  // maybe asKeyCode() would also be a nifty name :-)
        return keyCode;
   }

   public static ModifierCode fromKeyCode(KeyCode c) {
       for(ModifierCode m : values() ) {
            if( m.keyCode == c ) {
                return m;
            }
       }
       throw IllegalArgumentException("No MOdifierCode with that KeyCode!");
   }
}

Upvotes: 1

djechlin
djechlin

Reputation: 60788

I don't think anything like this is possible. The closest design suggestion I have is to make sure the enum is implementing an interface, then split it into two enums, one with the values with modifier keys and one without. Existing methods will take the interface, not the enum class. You should try to program to an interface and not an implementation anyway.

My guess is doing the runtime check is the best solution.

Upvotes: 0

Related Questions