12 Feb 2008

A better way to use Java Enum than switch

I think java enum are a nice addition to the language. I used to combine them with switch/case statements. But lately François, a colleague, shown we a better way :)

You can embedded behavior in each enumeration case, reducing client code and making it more elegant :)

Let's take a simple example: Every day of the week you need to do something: take out the garbage, go to the laundry etc. ...

Using switch here's how I would have done it:
    private enum Week {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}

public static void main(String[] args) {
final Week today = getToday();
Action action;
switch (today) {
case Sunday:
action = new FamillyDiner();
break;
case Monday:
case Friday:
action = new Garbage();
break;
case Tuesday:
action = new Laundry();
break;
case Wednesday:
action = new ChillOut();
break;
case Thursday:
action = new Grocery();
break;
case Saturday:
action = new SoccerGame();
break;
default:
throw new RuntimeException("Impossible day!");
}
action.execute();
}

Conclusion:
  • You can see the number of lines in main() is quite important
  • The client code (the switch/case code) is likely to be duplicate
  • There is an unnecessary case "default" that can never happen (even null case would result in a NullPointerException in the switch)
  • But it still much better than a if/elseif/else using int

Adding behavior to the enum:
    private enum Week {
Sunday {
@Override
public void execute() {
System.out.println("Mom and Dad diner.");
}
}, Monday {
@Override
public void execute() {
System.out.println("Take the garbage out.");
}
}, Tuesday {
@Override
public void execute() {
System.out.println("Do the laundry.");
}
}, Wednesday {
@Override
public void execute() {
System.out.println("Have a beer. Just Chill out!");
}
}, Thursday {
@Override
public void execute() {
System.out.println("Go out to the local store for Grocery with shoping list.");
}
}, Friday {
@Override
public void execute() {
System.out.println("Take the garbage out.");
}
}, Saturday {
@Override
public void execute() {
System.out.println("Manchester vs Arsenal! Can't miss that!");
}
};

public abstract void execute();
}

public static void main(String[] args) {
final Week today = getToday();
today.execute();
}

Conclusion:
  • Less lines of code and still readable
  • main() code is soooo easy
  • No unnecessary case "default"
  • If you don't want this behavior and still use the enum you are free to use the switch/case way


Clearly I think this approach is far better and much more elegant unless someone show me otherwise...



Download the complete code sample.

8 comments:

Anonymous said...

that's an interesting approach, but:
- default is optional in a switch
- it's less obvious in your code that 2 days share the same action
- a simple way to make main method cleaner in the switch solution is to create a getAction(Week) factory method.

Benjamin Francisoud said...

Thanks for sharing your remarks :)

- About "default is optional": yes I agree but that doesn't mean it can't happen, whereas with enum that default case can't happen...

- "less obvious code": agreed, it's less obvious. In the enum example, in a real world example, I would have move duplicated code to a separate method (making it a bit more obvious...)

- "create a getAction(Week)": agree too


My point was more about the fact that the switch/case still require more lines of code to do the same as the enum example for the same behavior...

Don't get me wrong the switch/case is perfectly fine and I've been writing such code for a long time. I don't plan to do a search and replace to remove such code in favor of the enum one;)

But I really find the enum example much neater, more elegant and less error prone.

I understand, it's also a matter of taste ;)

Anonymous said...

Interesting article :). Just a short comment :

enumeration should probably be considered as constants.
In order to reuse them, i think, it is advisable to not add business logic in there. BTW find here another interesting article about Java Enumerations, interfaces and internationalization

Anonymous said...

Cool stuff. It is kind of condition injection! Do not check for if/else later, build it along with the object. Thanks for sharing.

Онучин Артем said...

Just write now I'm rewriting very similar code from enum to switch style.

I had enum with two abstract methods: one method was used in one class and nowhere else and second method was used in another class and nowhere else.

In this case switch statement is more simple, all code is close. I don't have the entity that does nothing.

So enum is not the best choice in all cases.

Онучин Артем said...

I'm sorry for grammar mistakes: english is not my native laguage...

Singleton in Java said...

I agree Enum has made more power in Java language and thank its not copy paste from other language like C and C++. by using switch with enum makes code a lot cleaner and readable than if-else. You can also see some advanced samples of Enum in Java here.

Karthika Shree said...

It's interesting that many of the bloggers to helped clarify a few things for me as well as giving.Most of ideas can be nice content.The people to give them a good shake to get your point and across the command.
Java Training in Chennai