Java Enums at the parking lot.

As usual inside the office, an interview goes on, questions are made and questions that were left unanswered make the way through the rest of the team into the parking lot and end with two ThoughtWorkers testing at the parking lot theirs last assumptions. Well maybe this doesn't happen every time, but happened last Monday.

Java enums are a misunderstood feature but is a very useful one and candidates that I interview often don't what they can do with them. Here's a simple overview and some things that Aravind S.V. and I discussed at the parking lot.

First thing Java enums are classes, a special type but nevertheless classes, keep this in mind. What they a good for? Well, let's think about a type that have a finite (not so large) kinds, a Traffic Light per example can be RED, YELLOW and GREEN.

  public enum TrafficLight {
      RED, YELLOW, GREEN;
  }

That's nice, since a traffic light can't (at least in Brazil) have more states than these three colors an enum is pretty suited to do the job and in this case isn't even necessary to test it (till now). Remember, an enum is good for these cases, discrete, finite and short number of states. If for some reason you're not sure about the number of states just go for a interface and regular classes.

But enums aren't just little lists, they're classes, so they can have some behavior. In our traffic light let's add a method to check if a car can or can't cross given a certain light. Here's the tests:

  import org.junit.Test;

  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertTrue;

  public class TrafficLightTest {
      @Test
      public void carsCantCrossOnRedLIght() throws Exception {
          assertFalse(TrafficLight.RED.carCanCross());
      }

      @Test
      public void carsCanCrossOnYellowLight() throws Exception {
          assertTrue(TrafficLight.YELLOW.carCanCross());
      }

      @Test
      public void carsCanCrossOnGreenLight() throws Exception {
          assertTrue(TrafficLight.GREEN.carCanCross());
      }
  }

And the enum implementation:

  public enum TrafficLight {
      RED(false), YELLOW(true), GREEN(true);

      private boolean canCross;

      TrafficLight(boolean canCross) {
           this.canCross = canCross;
      }

      public boolean carCanCross() {
          return this.canCross;
      }
  }

That's awesome, our traffic light is not anymore a list of states but has some knowledge about it's state. Some things to note here, look that the constructor doesn't have an access modifier but as the Java specification goes it will be always private so you can't explicitly instantiate a enum. There's others things that come for free. An enum is Comparable and Serializable too, has a toString() that returns it's name and a name() method too that does the same.

Now let's add one more thing. Usually a traffic light changes from RED to GREEN, GREEN to YELLOW and YELLOW to RED, so I want my TrafficLight to do the same. Let's create a nextLight() method that returns the next one based on the current light. For now I will do the complicated way and refactor to a nice one. So I start adding some tests, my tests now look like this:

  import org.junit.Test;

  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertTrue;

  public class TrafficLightTest {
      @Test
      public void carsCantCrossOnRedLIght() throws Exception {
          assertFalse(TrafficLight.RED.carCanCross());
      }

      @Test
      public void carsCanCrossOnYellowLight() throws Exception {
          assertTrue(TrafficLight.YELLOW.carCanCross());
      }

      @Test
      public void carsCanCrossOnGreenLight() throws Exception {
          assertTrue(TrafficLight.GREEN.carCanCross());
      }

      @Test
      public void nextLightFromRedIsGreenLight() throws Exception {
          assertEquals(TrafficLight.GREEN,  TrafficLight.RED.nextLight());
      }

      @Test
      public void nextLightFromGreenIsYellowLight() throws Exception {
          assertEquals(TrafficLight.YELLOW, TrafficLight.GREEN.nextLight());
      }

      @Test
      public void nextLightFromYellowIsRedLight() throws Exception {
          assertEquals(TrafficLight.RED, TrafficLight.YELLOW.nextLight());
      }
  }

I was feeling kind lazy and made my IDE fix most of the code, look how TrafficLight is now:

  public enum TrafficLight {
      RED(false) {
          @Override
          public TrafficLight nextLight() {
              return GREEN;
          }
      }, YELLOW(true) {
          @Override
          public TrafficLight nextLight() {
              return RED;
          }
      }, GREEN(true) {
          @Override
          public TrafficLight nextLight() {
              return YELLOW;
          }
      };

      private boolean canCross;

      TrafficLight(boolean canCross) {
           this.canCross = canCross;
      }

      public boolean carCanCross() {
          return this.canCross;
      }

      abstract public TrafficLight nextLight();
  }

Uau, it works, but is messy. I just let stay this way for you to check that enums, since are classes, can implement methods inside them. When I've shown this during an interview the first reaction was "You're cheating!". In fact I'm not, is not a pleasant code to see but still is valid and has its merits. For example if you need an argument to your method process and give an answer, an enum is capable of doing that. But in this case we know everything so it's possible to simplify the enum. Like we did with the carCanCross() let's define beforehand the next light (warning! this doesn't compile!):

  public enum TrafficLight {

      RED(false, GREEN), YELLOW(true, RED), GREEN(true, YELLOW);

      private boolean canCross;
      private TrafficLight nextLight;

      TrafficLight(boolean canCross, TrafficLight nextLight) {
          this.canCross = canCross;
          this.nextLight = nextLight;
      }

      public boolean carCanCross() {
          return this.canCross;
      }

      public TrafficLight nextLight() {
          return this.nextLight;
      };
  }

This would be really nice each light defining it's next light but the compiler doesn't like it. IntelliJ will tell you Illegal forward reference. Before we wrote this code the discussion was if Java could do this or not, to make this possible it will have to defer the evaluation of the enum, well Java doesn't do this. The Java specification states on Enums:

It is a compile-time error to reference a static field of an enum type that is not a compile-time constant (§15.28) from constructors, instance initializer blocks, or instance variable initializer expressions of that type. It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant e to refer to itself or to an enum constant of the same type that is declared to the right of e.

So we can't do this nice implementation, our workaround to keep the layout of the code without explicitly telling the compiler what we want to do was to refer to the enum as a string, after that making the method nextLight() return the enum on the fly. The implementation looks like this:

  public enum TrafficLight {

      RED(false, "GREEN"), YELLOW(true, "RED"), GREEN(true, "YELLOW");

      private boolean canCross;
      private String nextLight;

      TrafficLight(boolean canCross, String nextLight) {
          this.canCross = canCross;
          this.nextLight = nextLight;
      }

      public boolean carCanCross() {
          return this.canCross;
      }

      public TrafficLight nextLight() {
          return TrafficLight.valueOf(this.nextLight);
      };
  }

It preservers the same idea but introduces strings that can be mistyped, the tests pass and we rely on them to keep the code right. That's it, remember that enums are more powerful than simple lists, you can add some behavior on them and have a testable and clean code. But as every feature of a language has to be used where is suitable.

Published in Apr 22, 2011