1

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?

djechlin
  • 59,258
  • 35
  • 162
  • 290
spilot
  • 625
  • 1
  • 7
  • 20
  • One question of course is whether the compiler *could* make this check for you. Is someone passing an arbitrary KeyCode in? Would you just have to wrap this message with the same check then cast to your hypothetical sub-enum? If so then there's no gain. (But no I don't think anything like this is possible.) – djechlin Jan 09 '16 at 01:21

2 Answers2

1

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!");
   }
}
thst
  • 4,592
  • 1
  • 26
  • 40
  • I thought about your last suggestion before, but the problem is that if I do this, I cannot pass the KeyCode to any javaFX functions anymore. – spilot Jan 09 '16 at 01:27
  • Not what I hoped for, but this is probably the best I can do. Thank you very much. I really don't see why extending enums the way I said is not possible. – spilot Jan 09 '16 at 10:02
  • You can find some high rated explanations here http://stackoverflow.com/questions/1414755/can-enums-be-subclassed-to-add-new-elements – thst Jan 09 '16 at 10:13
  • I have seen that before, but the question in that thread was whether there could be values _added_ by extending the enum. I see why that is no good idea. But creating a subset seems fine to me. – spilot Jan 09 '16 at 10:23
0

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.

djechlin
  • 59,258
  • 35
  • 162
  • 290
  • Your solution only works if you have control over the `enum` so you can split it up. Unfortunatly the `enum` `KeyCode` is part of the JDK and therefore for practical purposes unchangeable. – hotzst Jan 09 '16 at 08:16