Core Java

Featured enum instead of switch

Problem and  its solution

Switch/case is the common control structure implemented in most imperative programming languages. Switch is considered more readable than series of if/else.

Here is a simple example:

// Switch with int literal
switch (c) {
  case 1: one(); break;
  case 2: two(); break;
  case 3: three(); break;
  default: throw new UnsupportedOperationException(String.format("Operation %d is not supported", c));
}

Here is the list of the main problems in this code:

  1. Relationship between int literals (1, 2, 3) and executed code is not obvious.
  2. If one of the values (e.g. 2) becomes not supported anymore and this switch is not updated accordingly it will contain  forever the unused code.
  3. If new possible value of c (e.g. 4) is introduced and the switch is not updated accordingly the code will probably throw UnsupportedOperationException at runtime without any compile time notifications.
  4. Such switch structure tends to be duplicated several times in code that makes problems 2 and 3 even more complicated. 

The first simplest fix can be done by using int constants instead of literals. First, let’s define constants:

private static int ONE = 1;
private static int TWO = 2;
private static int THREE = 3;

Now the code will look like this:

switch (c) {
  case ONE: one(); break;
  case TWO: two(); break;
  case THREE: three(); break;
  default: throw new UnsupportedOperationException(String.format("Operation %d is not supported", c));
}

(Obviously in real life the names of the constants must be self descriptive)

This snippet is more readable but all other disadvantages are still relevant. The next attempt to improve the initial code snippet uses enums introduced to Java language in version 5 in 2004. Let’s define the followingenum:

enum Action {ONE, TWO, THREE}

Now the switch snippet will be slightly changed:

Action a = ...
switch (a) {
  case ONE: one(); break;
  case TWO: two(); break;
  case THREE: three(); break;
  default: throw new UnsupportedOperationException(String.format("Operation %s is not supported", a));
}

This code is a little bit better: it will produce compilation error if one of the elements is removed fromenum Action. However, it will not cause compilation error if additional element is added to enum Action. Some IDEs or static code analysis tools may produce warning in this case, but who is paying attention to warnings? Fortunately enum can declare abstract method that has to be implemented by each element:

enum Action {
  ONE { @Override public void action() { } }, 
  TWO { @Override public void action() { } }, 
  THREE { @Override public void action() { } }, 
  public abstract void action();
}

Now the switch statement can be replaced by single line:

Action a = ...
a.action();

This solution does not have any of disadvantages enumerated above:

  1. It is readable. The method is “attached” to enum element; one can write as many javadoc as it is needed if method meaning is unclear. The code that calls method is trivial: what can be simpler than method invocation?
  2. There is no way to removeenumconstant without removing the implementation, so no unused code will remain if some functionality is no longer relevant.
  3. Newenumelement cannot be added without implementation of method action(). Code without implementation can’t be compiled. 
  4. If several actions are required they all can be implemented in enum. As we already mentioned the code that calls specific function is trivial, so now there is no code duplication. 

Conclusion

Although switch/case structure is well known and widely used in various programming languages its usage may cause a lot of problems. Solution that uses  java enums and described above does not have these disadvantages. The nextarticle from this series shows how to extend functionality of existing enum.

Published on Java Code Geeks with permission by Alexander Radzin, partner at our JCG program. See the original article here: Featured enum instead of switch

Opinions expressed by Java Code Geeks contributors are their own.

Alexander Radzin

Alex is an experienced software engineer coding java and JVM based languages and technologies since 2000. Besides his work at the office he develops his own open source project at github and contributes code to other projects. Actively participated in StackOverflow community during several years.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

11 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
hamda
hamda
5 years ago

how we can instanciate the Action enumeration ?
could you please give an example for the same?
Thanks

msn734506700
msn734506700
5 years ago
Reply to  hamda

Action.ONE

Marc Dzaebel
Marc Dzaebel
5 years ago

Java 12 will improve switch syntax (https://dzone.com/articles/jdk-12-switch-statementsexpressions-in-action). If we do, what you intend, it might be easier to use:
enum Action implements Runnable {
ONE { @Override public void run() { } },
TWO { @Override public void run() { } },
THREE { @Override public void run() { } };
}

Note also, in your example, there is a comma instead of a semicolon, that make it uncompilable.

Krishna
Krishna
5 years ago

Interesting idea, but if we want to tie the action to the enum, why are we even using enum, why not create a base class and implement the concrete sub classes and call the action item on it?

Garry
Garry
5 years ago

I frequently have cases where I reference an ENUM but do different things depending on the context. This would work fine in cases where the ENUM only serves one limited and universal purpose. Otherwise I would find myself ignoring the method and using SWITCH statements like I do now. And I DO look for compilers warnings whenever I change an ENUM because it was an ENUM that was changed (pretty much only time I do actually).

robm99x
robm99x
3 years ago

I love adding functionality to enums and using enums as replacements for constants. They’re great for readability and no more need for switch() statements based on enumerated values.

Is there a “pattern” name for this? Its kinda of a cross between Singleton (there’s only 1 enum with that value) but also perhaps Strategy. Not sure. Anyways, I still use it to this day in my Java 8 coding. Can’t wait for Java 12 :-)

Stephan Wissel
1 year ago

I usually use a Map<MyEnum,Function with a getOrDefault. But storing the code with the enum is intriguing. Removes quite some boilerplate

Back to top button