Raging Goblin

10 June 2010

Switch over all values of a Java enum

Filed under: Java — Raging Goblin @ 06:29
Tags:

Suppose you want to switch over all values of an enum, how can you be sure you covered all cases? For example take this class with an inner enum type:

public class SwitchEnum {
   private enum values {VALUE1, VALUE2, VALUE3}
}

Now you want to switch over the elements of the enum, like this:

public class SwitchEnum {

 private void switchOverEnum(values value) {
  switch (value) {
  case VALUE1:
   // Do value 1 stuff
   break;
  case VALUE2:
   // Do value 2 stuff
   break;
  case VALUE3:
   // Do value 3 stuff
  }
 }

 private enum values {
  VALUE1, VALUE2, VALUE3
 }
}

In this academical example it is easy to see that you covered all possible values of the enum. But what if these values are in separate files? And don’t forget about the fallthrough way of switching in Java. Many devolopers consider this error-prone. I myself like this behavior but lets not start a flame war here. Imagine you are working with a couple of developers and another developer decides to create an extra value for the enum:

public class SwitchEnum {

 private void switchOverEnum(values value) {
  switch (value) {
  case VALUE1:
   // Do value 1 stuff
   break;
  case VALUE2:
   // Do value 2 stuff
   break;
  case VALUE3:
   // Do value 3 stuff
  }
 }

 private enum values {
  VALUE1, VALUE2, VALUE3, VALUE4
 }
}

Bummer, your switch statements did not cover this one and nothing will happen when the value parameter takes VALUE4. Yesterday a collegue of mine showed me a way to handle this.
First you add an Interface AbstractSwitch:

 private interface AbstractSwitch {

  public void caseValue1();

  public void caseValue2();

  public void caseValue3();
 }

Then you add an abstract method to your enum:

public abstract void enumSwitch(final AbstractSwitch switcher);

This will immediately lead to compile errors because the enum types have to override this method. When you use an IDE like eclipse you can simply type ctrl-1 an it will give you the option add unimplemented methods. After giving each enum value the right method our enum looks like this:

 private enum values {
  VALUE1 {
   @Override
   public void enumSwitch(AbstractSwitch switcher) {
    switcher.caseValue1();
   }
  },

  VALUE2 {
   @Override
   public void enumSwitch(AbstractSwitch switcher) {
    switcher.caseValue2();
   }
  },

  VALUE3 {
   @Override
   public void enumSwitch(AbstractSwitch switcher) {
    switcher.caseValue3();
   }
  };

  public abstract void enumSwitch(final AbstractSwitch switcher);
 }

Instead of switching over value, we call the enumSwitch method with an anonymous implementation of the AbstractSwitch interface:

private void switchOverEnum(values value) {
  value.enumSwitch(new AbstractSwitch() {

   @Override
   public void caseValue3() {
    // Do value 3 stuff
   }

   @Override
   public void caseValue2() {
    // Do value 2 stuff
   }

   @Override
   public void caseValue1() {
    // Do value 1 stuff
   }
  });
 }

Again this is easy with an IDE like eclipse because after typing new AbstractSwitch (maybe a ctrl-space will force this) it will provide a dropdown menu, and when you choose the right interface, the IDE will give you all methods as auto generated stubs.

What happens when you mysterious friend tries to add VALUE4? He will be forced to implement the enumSwitch method which will make him think about the AbstractSwitch interface and let him add a method to this one. But this will immediately lead to compile errors in all implementations of the AbstractSwitch interface forcing him to get in touch with you and find out what you want to do when the value parameter takes VALUE4. The complete code now looks like this:

 

public class SwitchEnum {

 private void switchOverEnum(values value) {
  value.enumSwitch(new AbstractSwitch() {

   @Override
   public void caseValue3() {
    // Do value 3 stuff
   }

   @Override
   public void caseValue2() {
    // Do value 2 stuff
   }

   @Override
   public void caseValue1() {
    // Do value 1 stuff
   }
  });
 }

 private enum values {
  VALUE1 {
   @Override
   public void enumSwitch(AbstractSwitch switcher) {
    switcher.caseValue1();
   }
  },

  VALUE2 {
   @Override
   public void enumSwitch(AbstractSwitch switcher) {
    switcher.caseValue2();
   }
  },

  VALUE3 {
   @Override
   public void enumSwitch(AbstractSwitch switcher) {
    switcher.caseValue3();
   }
  };

  public abstract void enumSwitch(final AbstractSwitch switcher);
 }

 private interface AbstractSwitch {

  public void caseValue1();

  public void caseValue2();

  public void caseValue3();
 }
}

Blog at WordPress.com.